Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. JavaScript

Как создать красивый виджет Календарь

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

В сегодняшнем премиальном учебнике и скринкасте я расскажу вам, как создать прозрачный календарный виджет. Мы будем использовать CSS3, чтобы придать ему блестящий внешний вид, а затем добавить некоторые довольно приятные функции с JavaScript.


Шаг 0. Идея

Я следую блогу 365PSD, действительно приятный сайт, который предлагает бесплатный PSD - обычно маленький фрагмент UI - каждый день. На 81-й день был действительно приятный виджет календаря. Я полагал, что не будет слишком сложно построить настоящую вещь, поэтому сегодня я покажу вам, как это сделать!



Шаг 1. HTML-код

Мы начнем с создания нашей структуры HTML. Конечно, мы начнем с каркаса:

Итак, внутри тела мы начнем с div, чтобы обернуть все это; затем в нем будет три основных раздела:

Во-первых, у нас есть div.header; оглядываясь назад на наш PSD, мы видим, что это соответствует верхней части, секции, которая содержит месяц, переключатели месяца и привязки. Затем у нас есть таблица с названиями дней. Наконец, у нас есть div#cal-frame. Это сетка календаря.

Я открою вам один секрет: когда я изначально построил пользовательский интерфейс этого календаря, у меня была только одна таблица с thead для дней и tbody для сетки календаря; но как только я начал писать JavaScript для переключения между месяцами, стало очевидно, что мне нужно использовать что-то более гибкое. Вы поймете, почему, когда мы доберемся до JavaScript.

Итак, это идет в заголовок:

У нас здесь пять элементов; на внешних сторонах у нас есть левый и правый переключатели календаря; так как я не хотел использовать какие-либо изображения в этом проекте, я нашел HTML-сущности &lang; и &rang (< и >, соответственно). Затем у нас есть два пустых промежутка для привязок календаря. Наконец, в середине у нас есть метка месяца/года.

Содержимое table#days довольно простое:

Наконец, у нас есть внутренности div#cal-frame; проверьте их, и затем мы обсудим это:


Полный скринкаст

 

Итак, что у нас здесь? В принципе, мы создаем сетку календаря с таблицей (позже мы будем динамически вставлять текущий месяц). Соответствующие ячейки имеют номера дат; если ячейки пусты, у них есть класс «nul»; наконец, сегодняшняя дата имеет класс «today».

И действительно, это голый HTML; пока не так много, но вот что мы имеем:



Шаг 2. CSS

Начнем с некоторого окружения:

Довольно очевидно, а? После установки цвета фона мы центрируем виджет календаря горизонтально и даем ему тень окна. Конечно, мы устанавливаем шрифт. Но почему мы устанавливаем отображение в таблицу? По умолчанию div будет отображаться в виде блока, что означает, что он займет всю доступную ширину; отображая его как таблицу, он будет занимать наименьшую ширину (пока он все еще содержит его дочерние элементы) и по-прежнему является блочным элементом.

Затем давайте сосредоточимся на панели заголовка:

Вот первая часть стиля заголовка; мы начинаем с установки курсора на указатель; текст, как правило, не будет выбираться. Затем мы установим красный цвет фона; однако, если браузер поддерживает его, мы будем использовать фоновый градиент: не забудьте добавить его как для mozilla, так и для webkit! Затем установите высоту 34px; мы установим положение относительное, потому что дочерние элементы будут позиционированы абсолютно; по положению родительского элемента относительно, дочерние будут помещены абсолютно по отношению к родителю, а не к body. Установите цвет текста на белый, вокруг верхнего левого и правого углов и сделайте шрифт полужирным. Затем создайте небольшую текстовую тень, чтобы текст выглядел c отступом. Наконец, преобразуйте текст в верхний регистр.

Каждый из элементов в заголовке представляет собой span; каждый из них будет отображаться как встроенный блок. Также дайте им высоту строки 34px (высота заголовка).

Эти span также имеют некоторые специальные классы, поэтому давайте посмотрим на них:

Во-первых, у нас класс «hook»; помните, что это хуки или привязки календаря. Мы установим ширину и высоту. Затем расположите это абсолютно. Затем мы сдвинем его снизу на 60%. Мы закроем угол, чтобы обернуть привязки. Затем мы установим цвет фона; если браузер поддерживает градиенты, мы переопределим сплошной фон с градиентом. Затем мы дадим им тень коробки.

Затем мы будем использовать классы местоположения, чтобы расположить хуки горизонтально; если элемент имеет как классы как «hook», так и «right», то переместите его на 15% справа; если у него есть класс «left», переместите его на 15% слева.

Теперь у нас есть кнопки переключения месяца:

Мы установим ширину на этих кнопках и центрируем текст; конечно, нам тоже нужно будет позиционировать их. Затем, для левой кнопки, мы перемещаем ее полностью влево и вверх по левому краю. Правая кнопка идет вправо и округляет верхний правый угол.

Наконец, мы добавим эффект нависания для кнопок; конечно, мы будем использовать градиент.

Есть еще один элемент для стилизации: это метка месяца.

Мы будем использовать letter-spacing, чтобы немного добавить расстояния между буквами. Затем мы даем span ширину 100% и центрируем текст. Поскольку все соседние элементы расположены абсолютно, давая это, полная ширина делает именно то, что мы хотим.

Вот и весь заголовок! Я должен упомянуть, что, хотя мы полностью позиционировали большинство элементов, так как мы используем проценты для их размещения, все отлично масштабируется, когда вы увеличиваете или уменьшаете размер шрифта в браузере.

Хорошо, давайте перейдем к заголовкам дней.

Мы начинаем с двух несколько более общих селекторов: заголовок дня и сетка календаря - это обе таблицы, поэтому первое правило применяется к обоим из них: мы устанавливаем фон в белый цвет и сворачиваем границы. Когда границы таблицы сжимаются, у них нет прокладки между ними. Затем для всех ячеек таблицы мы установим цвет текста, их ширину, высоту и высоту линии до 30 пикселей и затем центрируем текст. Все они получают границу и курсор по умолчанию (стрелка / указатель);

Затем добавим определенный стиль для ячеек таблицы в таблице дней: мы немного уменьшим их высоту и высоту строки, убедитесь, что они в верхнем регистре, и сбросьте размер шрифта и цвет текста. (Примечание: в сопроводительном скринкасте я написал #day вместо #days в селекторе для третьего блока выше и никогда не исправлял это, убедитесь, что вы поняли это правильно!)

Для чего это последнее правило? Ну, в настоящее время на ячейках имен дней есть светло-серые границы. Мы хотим изменить цвет границ справа на белый, чтобы они не были видны. Однако мы не хотим делать это у последней ячейки в строке. Итак, мы можем использовать два псевдокласса. :not будет принимать параметр «исключающий селектор». :last-child захватывает последний дочерний элемент, который мы уже выбрали: в этом случае это ячейки таблицы. Затем мы просто установим правую границу сплошным белым.

Эти два правила нацелены на сетку календаря. Для ячейки таблицы с классом «today» мы устанавливаем фон в светло-серый, а текст - на более темный серый цвет. Затем мы устанавливаем тень окна: это белая тень, но мы не используем размытие, так что это белая линия; мы подталкиваем его вверх и направо на один пиксель, поэтому получаем дополнительный эффект границы. Обратите внимание, что мы добавляем «вставку» в объявление теневой коробки, чтобы тень находилась внутри ячейки.

Следующее правило применяет эффект зависания ко всем ячейкам таблицы в сетке календаря, за исключением тех, которые с классом «nil»; мы устанавливаем текст в белый цвет и добавляем текстовую тень. Затем мы меняем фон на красный, используя градиент, когда можем. Мы включаем удаление теневой коробки специально для  ячейки с классом «today».

Есть особый случай, о котором мы еще не говорили; возьмите свой ближайший календарь - нет, не iCal, я говорю о реальном календарях из мертвых деревьев и откройте, о, скажем, октябрь 2010 года. Вы заметите, что на последней неделе есть удвоенная ячейка, с 24м и 31м в том же квадрате. Нам нужно это сделать, поэтому давайте добавим стили для этого.

То, как мы отметим это, заключается в том, что каждую дату в ячейке таблицы помещаем в span.

Во-первых, мы позиционируем span относительно и сжимаем их шрифт; Затем мы перемещаем первый вверх на 5px, а второй - вниз на 5px.

Мы сделаем еще одну вещь; когда мы переключаемся между месяцами, мы хотим чтобы один медленно исчезал; для этого требуется, чтобы две таблицы находились поверх друг друга. Мы можем достичь этого:

Тот, который мы угасаем, будет иметь класс «temp»; новый, который мы показываем, чтобы остаться (на некоторое время), будет иметь класс «curr».

И все это с помощью CSS! Теперь перейдем к некоторой функциональности.


Шаг 3. JavaScript

Мы сделаем функциональность для нашего календаря легкой для повторного использования; учитывая это, начнем:

Таким образом, мы создаем три функции внутри нашей функции CALENDAR; одна будет инициализировать виджет календаря, вторая будет перемещаться между месяцами, а третья будет создавать сетку календаря; обратите внимание на строку: createCal.cache = {}; мы обсудим это тоже!

Мы также создали три переменные наверху: мы дадим значения переменным wrap и label внутри init, а months - это массив с именами месяцев.

Вот содержание нашей функции init:

Начнем с того, что присвоим переменным wrap и label соответствующие значения: обратите внимание, что мы используем селектор, переданный в init, чтобы найти wrap, но возвращаемся к «#cal», если он не указан. Затем мы привязываем события click к следующей и предыдущей кнопкам календаря; они вызывают функцию switchMonth; если мы хотим следующий календарь, мы передаем true, иначе мы передаем false.

Однако switchMonth также может принимать еще два параметра; мы будем использовать их для события click на ярлыке. Когда пользователь нажимает имя месяца, мы должны перейти к текущему месяцу; поэтому мы переходим в текущий месяц и год, который мы можем получить из объекта JavaScript Date. Не забудьте установить параметр next в значение null!

Еще одна вещь (и бонусный совет, его нет в скринкасте!): Когда пользователь загружает страницу, мы хотим загрузить правильный месяц на месяц, который жестко закодирован. Самый простой способ сделать это - вызвать метод jQuery click на ярлыке без каких-либо параметров; это имитирует щелчок мышью и переводит календарь на текущий месяц.

Перейдем к функции switchMonth:

Мы установим несколько переменных вверху; мы разбиваем метку на массив под названием curr; мы также создаем переменную calendar и захватываем год текущего календаря.

Затем все становится сложнее. Я использовал условные операторы JavaScript, поэтому я могу поместить все это на одну строку. Вот что они делают:

Вы можете понять, почему условный оператор привлекателен: всего одна строка кода. Вот расширенная версия переменной года:

В конце всего, month и year будут правильными значениями для календаря, который мы пытаемся показать пользователю. Если вы почувствуете себя более комфортно, вы можете заменить эти две строки вышеприведенными фрагментами.

Затем мы создаем календарь и соответствующим образом корректируем DOM:

Что находится в объекте календаря, который возвращается из функции createCal? Это объект, например:

Мы обсудим, почему свойство calendar является методом, когда мы его создаем. А пока вернемся, чтобы поместить его на страницу. Мы получим фрейм календаря и найдем текущий календарь. Затем мы удалим класс «curr» и применим класс «temp»; затем мы помещаем новый календарь (который, кстати, идет с классом «curr»), а затем старый календарь исчезает и удаляется.

Итак, у нас есть еще одна функция: createCal.

Вот наш старт: переменные. У нас day, установлен в 1; у нас есть две переменных для итерации: i и j. Затем мы выясним, в какой день недели начинается месяц; мы можем сделать это, создав объект Date для первого дня месяца и вызвав getDay.

Затем мы создаем массив, который содержит количество дней в каждом месяце; для февраля нам нужно учитывать високосные годы, поэтому используйте другое тернарное выражение для расчета.

Наконец, у нас есть очень важная переменная calendar, которая представляет собой массив.

Затем мы хотим использовать то свойство cache, которое мы используем для функции createCal. (Поскольку все в JavaScript является объектом, даже функции могут иметь свойства.)

Вот что происходит: есть вероятность, что пользователь «запросит» один и тот же месяц более одного раза. Как только мы создадим его в первый раз, нет необходимости делать это снова; мы поместим его в кеш и вытащим его позже.

Если этот объект cache имеет свойство с именем года, который мы ищем, мы можем проверить доступность месяца; если мы уже сделали месяц, мы вернем этот кешированный объект. Если нет свойства для указанного года, мы создаем его, потому что нам нужно будет создать месяц, который мы собираемся затем тоже создать в нем.

Затем нам нужно начать создавать календарь для запрошенного месяца.

Это сложный момент; в то время как переменная hasDays истинна, мы знаем, что у нас осталось несколько дней в месяце. Поэтому мы будем использовать наш i-итератор для добавления недельного массива в массив календаря. Затем мы используем for-loop на j-итераторе, пока как он меньше 7; так как мы начинаем с 0, это даст нам 7 дней для недельного массива. Внутри нашего цикла есть три случая.

Во-первых, нам нужно проверить, находимся ли мы в первую неделю месяца; если так, то мы не обязательно начнем в первый день. Мы уже знаем, в какой день начинается месяц; это сохранено в нашей переменной startDay. Поэтому, если j === startDay, то мы на правильном дне, чтобы начать, поэтому мы поставим значение day в нужном слоте. Затем мы увеличиваем day и startDay на единицу. В следующий раз 'round for for loop, j и startDay будут такими же, так что они будут продолжать работать до конца недели.

Если мы не на первой неделе (i! == 0), то мы будем следить за тем, чтобы у нас осталось несколько дней, чтобы добавить в календарь; если это так, мы вставляем их в слоты. Наконец, если мы не на первой неделе, и у нас нет дней, чтобы добавить месяц, мы вместо этого добавим пустую строку. Затем мы установим hasDays в false.

В конце мы проверим, будет ли day больше, чем количество дней в месяце; если это так, мы установим hasDays в false. Это для специального случая, когда месяц заканчивается в субботу.

Конечно, не забывайте увеличивать i за пределами цикла for!

Мы не хотим, чтобы наш календарь имел более 5 недель; день или два попадут на шестую неделю, мы разделим ячейки на 5-й неделе, как мы уже подготовили в нашем CSS. Итак, если в календарном массиве есть 6 массив, мы будем перебирать его. Затем, если содержимое массива-элемента не является пустой строкой, мы переназначим значение ячейки непосредственно «выше» строки 6: мы обернем это значение в span и соединим другой span с соответствующим значением внутри строки 6. Это понятно?

Как только у нас будет все на месте, мы вырезаем последний элемент из calendar.

Теперь пришло время конкатенации каждой недели в нашем calendar; мы будем перебирать каждую из них в цикле for и переносить записи в строки таблицы, каждый день внутрь ячейки таблицы. Затем мы превратим все это в объект jQuery, после объединения всех строк таблицы и упаковки их таблицей. Затем мы добавим класс «curr» к этой таблице.

Все пустые ячейки таблицы (мы можем использовать псевдоселектор jQuery :empty, чтобы найти их), получат класс «nil».

Если мы создадим календарь для текущего месяца, мы найдем ячейку на сегодняшний день и дадим ей класс «today»; мы можем найти его, передав функцию в метод jQuery filter. Функция возвращает true, если текст ячейки соответствует дате.

Наконец, мы создадим наш законченный объект и поместим его в кеш. Почему мы создаем свойство calendar? Ну, если мы просто вернули объект jQuery, как только мы добавили его в календарь, а затем переместили его на другой месяц, таблица будет удалена из DOM; позже, если мы вернемся к этому месяцу, элемент не будет отображаться, потому что кэш ссылается на тот же элемент DOM. Поэтому мы используем метод clone jQuery для получения копии элемента DOM. Затем метка получает имя месяца из массива месяцев и объединяется с годом. Наконец, мы возвращаем объект.

Готово! Вернемся в файл index.html, добавим тег скрипта с этим:

Вот оно! Вот как выглядит наш готовый продукт!


Но я не могу показать вам функциональность; вам нужно будет проверить код самостоятельно! Спасибо за прочтение!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.