🗓️ JavaScript и HTML: делаем простой календарь за 5 минут

Существует много способов использования JS для вебмастера. Одним из таких примеров может быть виджет календаря для веб-страницы. В этом материале мы создадим такой виджет с помощью HTML, CSS и JavaScript.

Определимся с целями

Для вебмастера хорошей практикой является составление ТЗ для любой задачи. Даже если виджет планируется разместить на собственном сайте, pet-проекте или просто лабе, стоит определиться какие цели для пользователя будет выполнять этот виджет. В зависимости от целей мы будем писать функционал и оформление виджета. Календарь помогает пользователям просматривать расписание или информацию о событиях на определенный день или дату. Помимо этого, календарь может использоваться для выбора даты в планировщике событий или в других проектах.

Итак, наш будущий календарь будет:

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

Функционал довольно простой, но достаточный для демонстрации создания виджетов на JavaScript для веб-страниц. При желании его можно расширить дополнительными функциями в коде JS.

Календарь на JavaScript, HTML и CSS

Этот виджет календаря не требует внешних библиотек, поскольку он написан исключительно на JavaScript, CSS и HTML. Из внешних источников используется только Font Awesome CSS для клавиш навигации, но при желании их тоже можно заменить на собственные.

Ссылка на полный код в Codepen https://codepen.io/sergejkravchen2/pen/abVqxGv

Структура HTML

В HTML загрузите Reset CSS, чтобы очистить форматирование HTML-элементов в браузере по умолчанию. Аналогичным образом загрузите Font Awesome CSS для значков, добавив следующие ссылки CDN в тег заголовка вашей веб-страницы.

    <!-- Reset CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
    <!-- Font Awesome CSS  -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet" />  
    <!-- Calendar Style CSS -->
<link rel="stylesheet" href="scr/styles.css">

Нам нужен элемент div, в котором календарь будет отображаться динамически. Создайте элемент div с именем класса calendar-wrapper, разместите кнопки смены месяца «следующий/предыдущий» и элемент div с идентификатором divCal.

<div class="calendar-wrapper">
    <button id="btnPrev" type="button">Предыдущий</button>
    <button id="btnNext" type="button">Следующий</button>
<div id="divCal"></div>
</div>

Не забудьте добавить ссылку на будущий файл .js, где будет основной функционал.

 <script src="js/index.js"></script>

Вы можете разместить приведенную выше HTML-структуру в любом месте вашей веб-страницы/приложения, где вы хотите создать виджет календаря.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

Создание стилей CSS

После создания оболочки в HTML пришло время настроить макет календаря. Выберите класс calendar-wrapper и определите его ширину, поля, отступы и свойства границы следующим образом. Вы можете установить собственный цвет фона по вашему выбору.

.calendar-wrapper {
  width: 360px;
  margin: 3em auto;
  padding: 2em;
  border: 1px solid #dcdcff;
  border-radius: 5px;
  background: #fff;
}

Функция календаря генерирует даты, расположенные в виде таблицы. Таким образом, вы можете легко настроить макет календаря, выбрав элемент таблицы. Ниже приведены стили по умолчанию, вы можете изменить их в соответствии с вашими потребностями.

table {
  clear: both;
  width: 100%;
  border: 1px solid #dcdcff;
  border-radius: 3px;
  border-collapse: collapse;
  color: #444;
}
td {
  height: 48px;
  text-align: center;
  vertical-align: middle;
  border-right: 1px solid #dcdcff;
  border-top: 1px solid #dcdcff;
  width: 14.28571429%;
}
thead td {
  border: none;
  color: #28283b;
  text-transform: uppercase;
  font-size: 1.5em;
}

Класс not-current для элемента td указывает отключенные даты в календаре. Если вы хотите скрыть эти даты, вы можете использовать свойство видимости CSS со «скрытым» значением.

td.not-current {
  color: #c0c0c0;
}

Если вы хотите настроить текущую дату, вы можете выбрать today класс и определить для него стили CSS.

td.today {
  font-weight: 700;
  color: #28283b;
  font-size: 1.5em;
}

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

#btnPrev {
  float: left;
  margin-bottom: 20px;
}
#btnPrev:before {
  content: '\f104';
  font-family: FontAwesome;
  padding-right: 4px;
}
#btnNext {
  float: right;
  margin-bottom: 20px;
}
#btnNext:after {
  content: '\f105';
  font-family: FontAwesome;
  padding-left: 4px;
}
#btnPrev,
#btnNext {
  background: transparent;
  border: none;
  outline: none;
  font-size: 1em;
  color: #c0c0c0;
  cursor: pointer;
  font-family: sans-serif;
  text-transform: uppercase;
  transition: all 0.3s ease;
}

Также вы можете определить стиль наведения для кнопок «следующая/предыдущая».

#btnPrev:hover,
#btnNext:hover {
  color: #28283b;
  font-weight: bold;
}

Добавляем JavaScript

На этом этапе мы можем перейти к главному и добавить функцию JavaScript календаря в свой проект перед закрытием тега body.

var Cal = function(divId) {
  //Сохраняем идентификатор div
  this.divId = divId;
  // Дни недели с понедельника
  this.DaysOfWeek = [
    'Пн',
    'Вт',
    'Ср',
    'Чтв',
    'Птн',
    'Суб',
    'Вск'
  ];
  // Месяцы начиная с января
  this.Months =['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
  //Устанавливаем текущий месяц, год
  var d = new Date();
  this.currMonth = d.getMonth();
  this.currYear = d.getFullYear();
  this.currDay = d.getDate();
};
// Переход к следующему месяцу
Cal.prototype.nextMonth = function() {
  if ( this.currMonth == 11 ) {
    this.currMonth = 0;
    this.currYear = this.currYear + 1;
  }
  else {
    this.currMonth = this.currMonth + 1;
  }
  this.showcurr();
};
// Переход к предыдущему месяцу
Cal.prototype.previousMonth = function() {
  if ( this.currMonth == 0 ) {
    this.currMonth = 11;
    this.currYear = this.currYear - 1;
  }
  else {
    this.currMonth = this.currMonth - 1;
  }
  this.showcurr();
};
// Показать текущий месяц
Cal.prototype.showcurr = function() {
  this.showMonth(this.currYear, this.currMonth);
};
// Показать месяц (год, месяц)
Cal.prototype.showMonth = function(y, m) {
  var d = new Date()
  // Первый день недели в выбранном месяце 
  , firstDayOfMonth = new Date(y, m, 7).getDay()
  // Последний день выбранного месяца
  , lastDateOfMonth =  new Date(y, m+1, 0).getDate()
  // Последний день предыдущего месяца
  , lastDayOfLastMonth = m == 0 ? new Date(y-1, 11, 0).getDate() : new Date(y, m, 0).getDate();
  var html = '<table>';
  // Запись выбранного месяца и года
  html += '<thead><tr>';
  html += '<td colspan="7">' + this.Months[m] + ' ' + y + '</td>';
  html += '</tr></thead>';
  // заголовок дней недели
  html += '<tr class="days">';
  for(var i=0; i < this.DaysOfWeek.length;i++) {
    html += '<td>' + this.DaysOfWeek[i] + '</td>';
  }
  html += '</tr>';
  // Записываем дни
  var i=1;
  do {
    var dow = new Date(y, m, i).getDay();
    // Начать новую строку в понедельник
    if ( dow == 1 ) {
      html += '<tr>';
    }
    // Если первый день недели не понедельник показать последние дни предыдущего месяца
    else if ( i == 1 ) {
      html += '<tr>';
      var k = lastDayOfLastMonth - firstDayOfMonth+1;
      for(var j=0; j < firstDayOfMonth; j++) {
        html += '<td class="not-current">' + k + '</td>';
        k++;
      }
    }
    // Записываем текущий день в цикл
    var chk = new Date();
    var chkY = chk.getFullYear();
    var chkM = chk.getMonth();
    if (chkY == this.currYear && chkM == this.currMonth && i == this.currDay) {
      html += '<td class="today">' + i + '</td>';
    } else {
      html += '<td class="normal">' + i + '</td>';
    }
    // закрыть строку в воскресенье
    if ( dow == 0 ) {
      html += '</tr>';
    }
    // Если последний день месяца не воскресенье, показать первые дни следующего месяца
    else if ( i == lastDateOfMonth ) {
      var k=1;
      for(dow; dow < 7; dow++) {
        html += '<td class="not-current">' + k + '</td>';
        k++;
      }
    }
    i++;
  }while(i <= lastDateOfMonth);
  // Конец таблицы
  html += '</table>';
  // Записываем HTML в div
  document.getElementById(this.divId).innerHTML = html;
};
// При загрузке окна
window.onload = function() {
  // Начать календарь
  var c = new Cal("divCal");			
  c.showcurr();
  // Привязываем кнопки «Следующий» и «Предыдущий»
  getId('btnNext').onclick = function() {
    c.nextMonth();
  };
  getId('btnPrev').onclick = function() {
    c.previousMonth();
  };
}
// Получить элемент по id
function getId(id) {
  return document.getElementById(id);
}

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

Заключение

Ну вот мы наконец и перевернули наш календарь. Это довольно простой, но в то же время гибкий пример использования JS в веб-разработке. Виджет написан на чистом JS. При желании вы даже можете исключить из него Font Awesome CSS, чтобы убрать весь внешний код. Это никак не повлияет на функционал. Оформление можно сделать любым на усмотрение, а функционал календаря расширить, добавив собственные функции на ваше усмотрение.

Ссылка на полный код в codepen https://codepen.io/sergejkravchen2/pen/abVqxGv

Источники:

Материалы по теме

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

eFusion
01 марта 2020

ТОП-15 книг по JavaScript: от новичка до профессионала

В этом посте мы собрали переведённые на русский язык книги по JavaScript – ...
admin
10 июня 2018

Лайфхак: в какой последовательности изучать JavaScript

Огромный инструментарий JS и тонны материалов по нему. С чего начать? Расск...