В этом модуле мы шаг за шагом создадим полностью функциональный виджет календаря. Мы начнем с простых манипуляций с заголовком, затем перейдем к программной генерации сетки дней недели и чисел месяца. Вы закрепите навыки создания DOM-элементов через JavaScript (createElement), добавления их на страницу (append/appendChild), работы с CSS-классами (classList) и обработки событий (addEventListener). Все задания выполняются в контексте ограниченного пространства (виджет), что соответствует реальным задачам фронтенд-разработки.
- Модуль 1: Основы выбора элементов
- Выбор элемента по ID.
- Выбор элементов по классу.
- Выбор элементов по тегу.
- Выбор по селектору CSS.
- Выбор по атрибуту.
- Поиск элементов внутри другого элемента.
- Поиск родительского элемента.
- Поиск соседних элементов (предыдущий, следующий).
- Поиск первого и последнего дочернего элемента.
- Поиск всех дочерних элементов.
- Модуль 2: Манипуляция содержимым
- Модуль 3: Работа с атрибутами
- Модуль 4: Управление классами
- Модуль 5: Управление стилями
- Модуль 6: Создание и удаление элементов
- Создание нового элемента.
- Вставка элемента перед другим элементом.
- Вставка элемента после другого элемента.
- Добавление элемента в определенную позицию внутри списка дочерних элементов.
- Удаление элемента из DOM.
- Замена одного элемента другим.
- Перемещение существующего элемента в другое место DOM..
- Очистка содержимого элемента без его удаления.
- Модуль 7: Обработка событий
- Модуль 8: Работа с формами
- Модуль 9: Продвинутые манипуляции
- Модуль 10: Работа с размерами и прокруткой
- Получение размеров элемента.
- Получение позиции элемента относительно окна браузера.
- Получение позиции элемента относительно родительского элемента.
- Управление прокруткой страницы.
- Определение, виден ли элемент в текущей области просмотра.
- Плавная прокрутка к элементу.
- Создание элемента, который фиксируется при прокрутке.
- Модуль 11: Работа с медиа-элементами
- Модуль 12: Практические задания
Настройка заголовка календаря
Начнем с простого. У нас есть верстка календаря, но заголовок пуст. Вам нужно получить элемент заголовка по его ID и установить в него текст 'Октябрь 2023'. Это базовое действие для инициализации любого виджета.
.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; }
<div class="calendar">
<div id="month-year" class="header"></div>
<div id="calendar-body"></div>
</div>
// Находим элемент заголовка
const title = document.input__1("month-year");
// Устанавливаем текст
title.input__2 = "Октябрь 2023";
Генерация дней недели
Календарь немыслим без названий дней недели. Вместо того чтобы писать их вручную в HTML, давайте сгенерируем их из массива. Допишите цикл, который создает div для каждого дня и добавляет его в заголовок сетки.
.weekdays { display: grid; grid-template-columns: repeat(7, 1fr); background: #f0f0f0; } .day-name { padding: 5px; text-align: center; font-size: 12px; font-weight: bold; }
<div class="weekdays" id="weekdays-row"></div>
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);
});
Определение количества дней
Чтобы построить календарь правильно, нам нужно знать, сколько дней в текущем месяце. Используйте возможности объекта Date. Хитрость: если передать день '0' в следующий месяц, мы получим последний день текущего месяца.
body { font-family: sans-serif; padding: 20px; } #result { font-size: 20px; color: #333; }
<div>Дней в октябре 2023: <span id="result"></span></div>
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;
Цикл создания дней месяца
Теперь самое главное: заполним календарь числами. Нам нужно запустить цикл от 1 до 31 (результат из прошлого задания) и для каждого числа создать ячейку календаря.
.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; }
<div class="grid" id="days-grid"></div>
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);
}
Сдвиг начала месяца
1-е число месяца не всегда выпадает на понедельник. Если месяц начинается со среды, нам нужно добавить пустые ячейки перед 1-м числом. Допишите цикл, который создает пустые div-элементы для сдвига.
.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; }
<div class="grid" id="calendar"></div>
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);
}
Подсветка сегодняшней даты
Хороший календарь всегда показывает текущую дату. Внутри цикла генерации дней добавьте проверку: если текущее число 'i' совпадает с сегодняшним числом, добавьте ячейке специальный класс.
.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; }
<div class="grid" id="grid"></div>
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);
}
Выбор даты (Интерактивность)
Пользователь должен иметь возможность выбрать дату, кликнув на неё. Используем делегирование событий: повесим один обработчик на весь календарь и будем проверять, на какой элемент кликнули.
.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; }
<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>
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");
}
});
Переключение месяцев
Добавим кнопки 'Назад' и 'Вперед'. Вам нужно написать код для обработчика кнопки 'Вперед', который должен изменить текст в заголовке (имитация переключения).
.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; }
<div class="controls">
<button id="prev"><</button>
<span id="date-label">Сентябрь</span>
<button id="next">></button>
</div>
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 = "Август";
});