Создание интерактивного календаря

Тренажер по работе с HTML DOM на JavaScript для пользователей с начальным и средним уровнем подготовки.

Тренажер JavaScript: Покоряем HTML DOM

В этом модуле мы шаг за шагом создадим полностью функциональный виджет календаря. Мы начнем с простых манипуляций с заголовком, затем перейдем к программной генерации сетки дней недели и чисел месяца. Вы закрепите навыки создания DOM-элементов через JavaScript (createElement), добавления их на страницу (append/appendChild), работы с CSS-классами (classList) и обработки событий (addEventListener). Все задания выполняются в контексте ограниченного пространства (виджет), что соответствует реальным задачам фронтенд-разработки.

Список тем

Настройка заголовка календаря

id: 37089_calendar_task_1

Начнем с простого. У нас есть верстка календаря, но заголовок пуст. Вам нужно получить элемент заголовка по его ID и установить в него текст 'Октябрь 2023'. Это базовое действие для инициализации любого виджета.

CSS
.calendar { font-family: sans-serif; width: 100%; max-width: 350px; border: 1px solid #ccc; padding: 10px; } .header { text-align: center; font-weight: bold; font-size: 18px; margin-bottom: 10px; }
HTML
Восстановить HTML
<div class="calendar">
  <div id="month-year" class="header"></div>
  <div id="calendar-body"></div>
</div>
JavaScript
// Находим элемент заголовка
const title = document.input__1("month-year");

// Устанавливаем текст
title.input__2 = "Октябрь 2023";
Используйте метод document.getElementById для поиска элемента и свойство textContent (или innerText) для изменения его содержимого.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Генерация дней недели

id: 37089_calendar_task_2

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

CSS
.weekdays { display: grid; grid-template-columns: repeat(7, 1fr); background: #f0f0f0; } .day-name { padding: 5px; text-align: center; font-size: 12px; font-weight: bold; }
HTML
Восстановить HTML
<div class="weekdays" id="weekdays-row"></div>
JavaScript
const days = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"];
const container = document.getElementById("weekdays-row");

days.forEach(day => {
  // Создаем div для дня недели
  const dayEl = document.input__1("div");
  
  // Записываем название дня
  dayEl.textContent = day;
  
  // Добавляем класс для стилизации
  dayEl.classList.input__2("day-name");
  
  // Добавляем элемент в контейнер
  container.input__3(dayEl);
});
Внутри цикла forEach создавайте элемент через createElement, добавляйте ему текст и затем вставляйте в родительский контейнер.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Определение количества дней

id: 37089_calendar_task_3

Чтобы построить календарь правильно, нам нужно знать, сколько дней в текущем месяце. Используйте возможности объекта Date. Хитрость: если передать день '0' в следующий месяц, мы получим последний день текущего месяца.

CSS
body { font-family: sans-serif; padding: 20px; } #result { font-size: 20px; color: #333; }
HTML
Восстановить HTML
<div>Дней в октябре 2023: <span id="result"></span></div>
JavaScript
const year = 2023;
const month = 9; // Октябрь (месяцы начинаются с 0)

// Получаем дату: 0-й день следующего месяца (это последний день текущего)
// month + 1 это ноябрь, день 0 вернет 31 октября
const dateInfo = new input__1(year, month + 1, 0);

// Получаем число дней (31)
const daysCount = dateInfo.input__2();

document.getElementById("result").textContent = daysCount;
Конструктор new Date(year, month, day) позволяет получить дату. Метод getDate() вернет число месяца.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Цикл создания дней месяца

id: 37089_calendar_task_4

Теперь самое главное: заполним календарь числами. Нам нужно запустить цикл от 1 до 31 (результат из прошлого задания) и для каждого числа создать ячейку календаря.

CSS
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; max-width: 300px; } .day { background: #eee; padding: 10px; text-align: center; font-family: sans-serif; cursor: pointer; } .day:hover { background: #ddd; }
HTML
Восстановить HTML
<div class="grid" id="days-grid"></div>
JavaScript
const grid = document.getElementById("days-grid");
const daysInMonth = 31;

for (let i = 1; i <= daysInMonth; i++) {
  let dayCell = document.createElement("div");
  
  // Добавляем текст (число месяца)
  dayCell.textContent = input__1;
  
  // Добавляем класс
  dayCell.className = "day";
  
  // Вставляем ячейку в сетку
  grid.input__2(dayCell);
}
Используйте цикл for. Внутри создавайте div, добавляйте ему класс 'day' и текст, равный индексу цикла.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Сдвиг начала месяца

id: 37089_calendar_task_5

1-е число месяца не всегда выпадает на понедельник. Если месяц начинается со среды, нам нужно добавить пустые ячейки перед 1-м числом. Допишите цикл, который создает пустые div-элементы для сдвига.

CSS
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; max-width: 300px; border: 1px solid #ccc; } .day, .empty { height: 30px; display: flex; align-items: center; justify-content: center; font-family: sans-serif; } .day { background: #e3f2fd; } .empty { background: #fff; }
HTML
Восстановить HTML
<div class="grid" id="calendar"></div>
JavaScript
const calendar = document.getElementById("calendar");
const startDay = 2; // Допустим, месяц начинается со среды (0-Пн, 1-Вт, 2-Ср)

// Цикл для пустых ячеек
for (let i = 0; i < input__1; i++) {
  let emptyCell = document.createElement("div");
  emptyCell.classList.add("empty");
  calendar.appendChild(emptyCell);
}

// Добавим пару дней для примера
for(let k=1; k<=5; k++) {
  let d = document.createElement("div");
  d.textContent = k;
  d.classList.add("day");
  calendar.appendChild(d);
}
В этом примере startDay = 2 (Среда, если считать Пн=0). Нам нужно создать 2 пустых блока перед началом нумерации.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Подсветка сегодняшней даты

id: 37089_calendar_task_6

Хороший календарь всегда показывает текущую дату. Внутри цикла генерации дней добавьте проверку: если текущее число 'i' совпадает с сегодняшним числом, добавьте ячейке специальный класс.

CSS
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; max-width: 300px; } .day { padding: 10px; text-align: center; border: 1px solid #eee; } .today { background-color: #ffeb3b; font-weight: bold; border-color: #fbc02d; }
HTML
Восстановить HTML
<div class="grid" id="grid"></div>
JavaScript
const grid = document.getElementById("grid");
const today = 15; // Представим, что сегодня 15-е число

for (let i = 1; i <= 31; i++) {
  let cell = document.createElement("div");
  cell.textContent = i;
  cell.classList.add("day");
  
  // Проверка: если i равно сегодня
  if (i === input__1) {
     cell.classList.input__2("today");
  }
  
  grid.appendChild(cell);
}
Вам нужно сравнить переменную цикла 'i' с 'today'. Если они равны, используйте classList.add для добавления класса 'today'.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Выбор даты (Интерактивность)

id: 37089_calendar_task_7

Пользователь должен иметь возможность выбрать дату, кликнув на неё. Используем делегирование событий: повесим один обработчик на весь календарь и будем проверять, на какой элемент кликнули.

CSS
.grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; max-width: 300px; font-family: sans-serif; } .day { padding: 10px; background: #eee; cursor: pointer; text-align: center; } .day.selected { background: #4caf50; color: white; }
HTML
Восстановить HTML
<div class="grid" id="calendar-wrap">
  <div class="day">1</div><div class="day">2</div><div class="day">3</div>
  <div class="day">4</div><div class="day">5</div><div class="day">6</div>
</div>
JavaScript
const wrap = document.getElementById("calendar-wrap");

wrap.addEventListener("click", function(event) {
  // Проверяем, содержит ли элемент класс 'day'
  if (event.input__1.classList.contains("day")) {
    
    // Очищаем предыдущее выделение (упрощенно)
    document.querySelectorAll('.selected').forEach(el => el.classList.remove('selected'));
    
    // Добавляем класс selected элементу, по которому кликнули
    event.target.classList.input__2("selected");
  }
});
В обработчике события 'e' свойство target указывает на элемент, по которому кликнули. Проверьте, содержит ли этот элемент класс 'day'.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку

Переключение месяцев

id: 37089_calendar_task_8

Добавим кнопки 'Назад' и 'Вперед'. Вам нужно написать код для обработчика кнопки 'Вперед', который должен изменить текст в заголовке (имитация переключения).

CSS
.controls { display: flex; justify-content: space-between; align-items: center; max-width: 300px; margin-bottom: 10px; font-family: sans-serif; } button { padding: 5px 10px; cursor: pointer; }
HTML
Восстановить HTML
<div class="controls">
  <button id="prev"><</button>
  <span id="date-label">Сентябрь</span>
  <button id="next">></button>
</div>
JavaScript
const nextBtn = document.querySelector("#next");
const label = document.querySelector("#date-label");

// Добавляем обработчик клика
nextBtn.input__1("click", function() {
  label.textContent = "Октябрь";
});

// Аналогично для кнопки назад (уже написано)
document.querySelector("#prev").addEventListener("click", () => {
  label.input__2 = "Август";
});
Найдите кнопку по ID и добавьте ей слушатель события 'click'.
Заполнить ответами все поля
Результат
Лог
Выполнить
Показать подсказку
НайтиКурс.Ру