Blog. Just Blog

Календарь на JavaScript

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Для одного из рабочих проектов мне потребовался календарик на JavaScript. Можно было, конечно, поискать что-то готовое, но гораздо приятнее написать собственный вариант. В результате был написан вот такой кроссбраузерный скрипт календаря, который легко дополняется любыми нужными функциями. Например, в рабочем проекте была добавлена проверка, чтобы пользователь не мог выбрать дни и листать месяцы далее определенной даты. Здесь я выкладываю только базовый вариант скрипта без дополнительных наворотов. Код подробно прокомментирован, с его пониманием проблем быть не должно.
  1. // Скрипт календарика с возможностью выбора даты
  2. calendar = {};
  3.  
  4. // Названия месяцев
  5. calendar.monthName=[
  6.   'Январь''Февраль''Март''Апрель',
  7.   'Май''Июнь''Июль''Август',
  8.   'Сентябрь''Октябрь''Ноябрь''Декабрь'
  9. ];
  10.  
  11. // Названия дней недели
  12. calendar.dayName=[
  13.   'ПН''ВТ''СР''ЧТ''ПТ''СБ''ВС'
  14. ];
  15.  
  16. // Выбранная дата
  17. calendar.selectedDate = {
  18.   'Day' null,
  19.   'Month' null,
  20.   'Year' null
  21. };
  22.  
  23. // ID элемента для размещения календарика
  24. calendar.element_id=null;
  25.  
  26. // Выбор даты
  27. calendar.selectDate = function(day,month,year) {
  28.   calendar.selectedDate={
  29.     'Day' day,
  30.     'Month' month,
  31.     'Year' year
  32.   };
  33.   calendar.drawCalendar(month,year);
  34. }
  35.  
  36. // Отрисовка календарика на выбранный месяц и год
  37. calendar.drawCalendar = function(month,year) {
  38.   var tmp='';
  39.   tmp+='<table class="calendar" cellspacing="0" cellpadding="0">';
  40.  
  41.   // Месяц и навигация
  42.   tmp+='<tr>';
  43.   tmp+='<td class="navigation" '+
  44.        'onclick="calendar.drawCalendar('+(month>1?(month-1):12)+
  45.        ','+(month>1?year:(year-1))+');">&#9668;<\/td>';
  46.   tmp+='<td colspan="5" class="navigation" '+
  47.        'onclick="calendar.drawCalendar('+
  48.        calendar.selectedDate.Month+','+
  49.        calendar.selectedDate.Year+');">'+
  50.        calendar.monthName[(month-1)]+'&nbsp;-&nbsp;'+year+'<\/td>';
  51.   tmp+='<td class="navigation" '+
  52.        'onclick="calendar.drawCalendar('+(month<12?(month+1):1)+
  53.        ','+(month<12?year:(year+1))+');">&#9658;<\/td>';
  54.   tmp+='<\/tr>';
  55.  
  56.   // Шапка таблицы с днями недели
  57.   tmp+='<tr>';
  58.   tmp+='<th>'+calendar.dayName[0]+'<\/th>';
  59.   tmp+='<th>'+calendar.dayName[1]+'<\/th>';
  60.   tmp+='<th>'+calendar.dayName[2]+'<\/th>';
  61.   tmp+='<th>'+calendar.dayName[3]+'<\/th>';
  62.   tmp+='<th>'+calendar.dayName[4]+'<\/th>';
  63.   tmp+='<th class="holiday">'+calendar.dayName[5]+'<\/th>';
  64.   tmp+='<th class="holiday">'+calendar.dayName[6]+'<\/th>';
  65.   tmp+='<\/tr>';
  66.  
  67.   // Количество дней в месяце
  68.   var total_days 32 - new Date(year, (month-1), 32).getDate();
  69.   // Начальный день месяца
  70.   var start_day = new Date(year, (month-1), 1).getDay();
  71.   if (start_day==0) { start_day=7; }
  72.   start_day--;
  73.   // Количество ячеек в таблице
  74.   var final_index=Math.ceil((total_days+start_day)/7)*7;
  75.  
  76.   var day=1;
  77.   var index=0;
  78.   do {
  79.     // Начало строки таблицы
  80.     if (index%7==0) {
  81.       tmp+='<tr>';
  82.     }
  83.     // Пустые ячейки до начала месяца или после окончания
  84.     if ((index<start_day) || (index>=(total_days+start_day))) {
  85.       tmp+='<td class="grayed">&nbsp;<\/td>';
  86.     }
  87.     else {
  88.       var class_name='';
  89.       // Выбранный день
  90.       if (calendar.selectedDate.Day==day &&
  91.           calendar.selectedDate.Month==month &&
  92.           calendar.selectedDate.Year==year) {
  93.         class_name='selected';
  94.       }
  95.       // Праздничный день
  96.       else if (index%7==|| index%7==5) {
  97.         class_name='holiday';
  98.       }
  99.       // Ячейка с датой
  100.       tmp+='<td class="'+class_name+'" '+
  101.            'onclick="calendar.selectDate('+
  102.            day+','+month+','+year+');">'+day+'<\/td>';
  103.       day++;
  104.     }
  105.     // Конец строки таблицы
  106.     if (index%7==6) {
  107.       tmp+='<\/tr>';
  108.     }
  109.     index++;
  110.   }
  111.   while (index<final_index);
  112.  
  113.   tmp+='<\/table>';
  114.  
  115.   // Вставить таблицу календарика на страницу
  116.   var el=document.getElementById(calendar.element_id);
  117.   if (el) {
  118.     el.innerHTML=tmp;
  119.   }
  120. }
Скрипт рисует таблицу с календарем на выбранный месяц и год, с названием месяца в заголовке, а также с кнопками листания на следующий и предыдущий месяц. Суббота и воскресенье выделены цветом. Кликнув на любую дату, пользователь может выбрать ее для дальнейшей обработки в других скриптах. Клик по названию месяца в заголовке возвращает календарь на месяц, в котором находится выбранная дата.

Из интересных плюшек хотел бы обратить ваше внимание на код для определения количества дней в месяце. В JavaScript штатных функция для этого нет, но есть вот такой красивый вариант. Рекомендую его запомнить, он может пригодиться и в других проектах.
  1. // year - год
  2. // month [0..11] - месяц
  3. total_days 32 - new Date(yearmonth32).getDate();
  4. // теперь в total_days количество дней в месяце
Внешний вид календарика настраивается при помощи CSS. Я привожу здесь минимально необходимые настройки стилей, при необходимости вы можете их изменить под свои нужды.
  1. /* Таблица календарика */
  2. .calendar {
  3.   border1px solid #909090;
  4.   border-collapsecollapse;
  5.   font-familyArial;
  6.   font-size14px;
  7. }
  8. /* Заголовок */
  9. .calendar th {
  10.   text-aligncenter;
  11.   width36px;
  12.   height36px;
  13.   background#D0D0D0;
  14.   color#000000;
  15.   border1px solid #909090;
  16. }
  17. /* Заголовок праздника */
  18. .calendar th.holiday {
  19.   color#FF0000;
  20. }
  21. /* Ячейка дня */
  22. .calendar td {
  23.   text-alignright;
  24.   width28px;
  25.   height36px;
  26.   padding-right8px;
  27.   border1px solid #909090;
  28.   text-alignright;
  29.   cursorpointer;
  30. }
  31. /* Затемненный день */
  32. .calendar td.grayed {
  33.   background#F0F0F0;
  34.   cursorauto !important;
  35. }
  36. /* Выбранный день */
  37. .calendar td.selected {
  38.   background#6DAFBF;
  39.   color#FFFFFF;
  40.   box-shadow1px 1px rgba(2552552550.5inset;
  41. }
  42. /* Праздничный день */
  43. .calendar td.holiday {
  44.   color#FF0000;
  45. }
  46. /* Кнопки навигации */
  47. .calendar td.navigation {
  48.   text-aligncenter;
  49.   border0px none !important;
  50.   font-size20px;
  51.   cursorpointer;
  52.   white-spacenowrap;
  53. }
После размещения скрипта его надо инициализировать и запустить. Делается это следующим образом. Сперва надо установить начальную дату, например, сегодняшний день. Затем надо задать ID элемента страницы, в котором будет отображаться календарик, и выполнить функцию calendar.drawCalendar с параметрами нужного месяца и года.
  1. // ID элемента для размещения календарика
  2. calendar.element_id 'calendar_table';
  3.  
  4. // По умолчанию используется текущая дата
  5. calendar.selectedDate={
  6.   'Day' : new Date().getDate(),
  7.   'Month' parseInt(new Date().getMonth(),10)+1,
  8.   'Year' : new Date().getFullYear()
  9. };
  10.  
  11. // Нарисовать календарик
  12. calendar.drawCalendar(
  13.   calendar.selectedDate.Month,
  14.   calendar.selectedDate.Year
  15. );
Когда вы работаете с web-страницей, выбранная в календарике дата в любой момент доступна через свойства объекта calendar.selectedDate, а свой обработчик выбранной даты вы можете добавить в функцию calendar.selectDate. Посмотреть пример рабочего календарика можно на демонстрационной странице. Как указано в статье, начальной датой выставляется сегодняшний день, стили тоже такие же.

Поделиться ссылкой ВКонтакте
Просмотров: 18010 | Комментариев: 25

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (15.10.2019 в 15:52):
Через кассу
Мария (14.10.2019 в 14:09):
Добрый день!
Подскажите, пожалуйста, как прописать в коде чтобы отображался квартал, 3 месяца, а не один.

Заранее благодарю!
Любовь (02.11.2017 в 22:52):
ManHunter, Я уже кучу времени потратила на попытки реализации и перепробовала множество способов. Например :

<input id='MyDate' type='text' readonly>
<script>
var MyDate.value=calendar.selectedDate;
</script>

Или же просто для вывода на экран:

<a onclick="alert(calendar.selectedDate);">
Узнать дату </a>

Можно к вам как то обратиться за помощью?
ManHunter (02.11.2017 в 20:58):
ЦитатаКогда вы работаете с web-страницей, выбранная в календарике дата в любой момент доступна через свойства объекта calendar.selectedDate

Вот и присваивай это значение нужному полю ввода или куда там оно требуется.
Любовь (02.11.2017 в 18:59):
Здравствуйте. Как можно организовать вывод выбранной даты в отдельное поле с помощью calendar.selectDate?
Алексей (19.04.2017 в 15:45):
Спасибо!
Александр (23.09.2014 в 18:42):
не подскажешь, почему при клике на календарь, он исчезает, а с инпут все норм? По идеи я догадываюсь зачем, но не подскажешь как сделать?
Александр (19.09.2014 в 23:34):
Это не то, вот решение этому:
  document.onclick = function(ev) {
    myDiv = document.getElementById('calendar_table');
    myDate = document.getElementById('calendar_date'); //input
    if (ev.target.id != myDiv.id && ev.target.id != myDate.id && myDiv.style.display == 'block')  {
      myDiv.style.display = 'none';
    }
  }
Также сделал правку в классе...
ManHunter (19.09.2014 в 20:39):
onclick на body или другом обрамляющем элементе
Александр (19.09.2014 в 20:31):
Я имел ввиду после окончания месяца, но я ошибся (для этого просто сделал новую переменную и плюсовал в цикле, а до этого как вы сказали, но еще плюсовал 1). Также я его чуток доработал и сделал кнопки покрасивее. исходник могу скинуть. Я не совсем профи с жаваскрипт, поэтому не могли бы подсказать как сделать событие клика на пустом месте документа(при клике на инпут, он показывается)?
ManHunter (16.09.2014 в 21:41):
Я бы присвоил index2 значение (количество дней в предыдущем месяце - start_day) а потом внутри цикла его плюсовал. Как-то так.
Александр (16.09.2014 в 21:33):
else if (index>=(total_days+start_day)) {       
    index2 = index-total_days+1;
    tmp+='<td class="grayed">'+index2+'<\/td>';
}
Вы бы также сделали бы?

Ой, неверно.
ManHunter (16.09.2014 в 21:16):
Совершенно верно.
Александр (16.09.2014 в 21:11):
Я так понял надо сделать соответствующий код сюда if (index<start_day) {} и сюда else if (index>=(total_days+start_day)) {} ?
ManHunter (16.09.2014 в 21:03):
Я почти всегда в курсе, что происходит на сайте )
Александр (16.09.2014 в 20:59):
ManHunter, спасибо. Попробую сейчас реализовать. Не ожидал, что так быстро ответите
ManHunter (16.09.2014 в 20:48):
Посчитать по аналогии прошлый месяц, заполнить первые ячейки. Следующий месяц от 1 числа до конца последних пустых ячеек.
Александр (16.09.2014 в 20:43):
Как сделать чтобы в пустых ячейках были даты прошлого и будущего месяца?
ManHunter (01.04.2014 в 12:12):
Лабораторные работы делаются за деньги. Не можешь делать сам - платишь тем, кто может.
Сергей (01.04.2014 в 12:11):
Я понимаю что я задаю глупые вопросы, с программирование на 3 максимум)) но это надо попытаться реализовать)

Еще у меня такой вопрос
хотелось бы добавить сверху возможность смены года (ну и соответственно чтобы месяца перерисовывал в соответствии с годом)
Можете подсказать как это реализовать с вашим кодом? ))
Заранее спасибо)
ManHunter (01.04.2014 в 07:16):
// Количество ячеек в таблице
var final_index=сколько надо

Может найти себе другое занятие, если в коде с подробными комментариями возникают такие вопросы?
Сергей (01.04.2014 в 01:38):
Возник другой вопрос))
как сделать, чтобы для чисел кол-во ячеек всегда было 6 (чтобы месяца ровно отображались, а то у кого то 5 строчек для чисел, а у другого 6, и получается криво) ?
Заранее большое спасибо)
Сергей (31.03.2014 в 23:48):
Спасибо))
ManHunter (31.03.2014 в 23:40):
Разметка года таблицей, ячейки от id="month_1" до "month_12"
В цикле
calendar.element_id='month_'+i
...
'Month' : i
В основном коде убрать навигацию. Все.
Сергей (31.03.2014 в 23:31):
У меня вот такой вопрос.

Я хочу чтобы был не один месяц на странице а сразу год целиком.
Хотел сделать это через цикл for и указанием в html data-m="0" (и так для всех месяцев)

Как перебрать этот код (навигацию в месяце уберу), чтобы не писать новый, чтобы он год целиком?

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0055 сек.) / Память: 4.5 Mb
Наверх