Календари стали неотъемлемой частью современных веб-приложений, поскольку они позволяют пользователям организовывать, планировать и отслеживать события без проблем. Независимо от того, создаёте ли вы инструмент управления проектами, приложение для планирования событий или персональный набор продуктивности, пользовательский календарный компонент может значительно улучшить опыт использования. В то время как существует множество готовых календарных библиотек, создание собственного компонента может обеспечить гибкость для удовлетворения конкретных требований к дизайну и функциональности.
В этом руководстве мы исследуем, как создать компонент, подобный календарю Google, используя JavaScript. К концу этого руководства у вас будет полностью функциональный календарь с интерактивными функциями и более глубоким пониманием того, как создавать повторно используемые компоненты для веб-приложений. Независимо от того, являетесь ли вы разработчиком, стремящимся добавить уникальное прикосновение к своему проекту, или человеком, желающим узнать внутреннее устройство функциональности календаря, этот пошаговый обзор будет бесценным. Давайте начнем!
Обзор
Мы создадим календарный компонент со следующими функциями:
- Ось времени: Вертикальная шкала времени с 12:00 ночи до 23:00.
- Блоки событий: Динамически отображаемые события с правильным позиционированием и высотой на основе их начального и конечного времени.
- Обработка перекрытий: События, перекрывающиеся во времени, будут отображаться бок о бок.
Вот как вы можете создать этот компонент пошагово.
Пошаговое руководство
1. Настройка HTML и основных стилей
Начнем с создания минимальной структуры HTML для календаря. Макет включает в себя ленту времени и контейнер для событий.
<div class="calendar">
<div class="calendar-time">
<ul id="timelist" class="calendar-timelist"></ul>
</div>
<div id="events" class="calendar-events"></div>
</div>
Добавьте базовый CSS для стилизации календаря:
.calendar {
display: flex;
width: 500px;
margin: 20px auto;
position: relative;
}
.event {
background: #039be5;
border: 1px solid white;
border-radius: 5px;
position: absolute;
box-sizing: border-box;
color: white;
overflow: hidden;
padding: 3px;
}
.calendar-time {
border-right: 1px solid #ccc;
width: 100px;
}
.calendar-timelist {
list-style: none;
padding: 0;
margin: 0;
text-align: right;
padding-right: 20px;
}
.calendar-timelist li {
height: 60px;
box-sizing: border-box;
width: 100%;
}
.calendar-events {
flex-grow: 1;
position: relative;
}
2. Создание класса JavaScript для календаря
Определите класс Calendar
для инкапсуляции всей функциональности.
Конструктор
Конструктор инициализирует календарь путем отображения ленты времени и событий:
class Calendar {
constructor(data) {
// Render the timeline on the Y-axis
this.renderTime();
// Render the event blocks
this.renderEvents(data);
}
renderTime() {
let timeHTML = Array.from({ length: 24 }, (_, i) => `<li>${this.to12HourFormat(i)}</li>`).join("");
document.getElementById("timelist").innerHTML = timeHTML;
}
renderEvents(data) {
let groupedEvents = this.groupEvents(data);
let eventData = this.calculateEventStyles(groupedEvents);
let eventHTML = eventData
.map(
(e) =>
`<div class="event" style="top: ${e.top}px; height: ${e.height}px; width: ${e.width}%; left: ${e.left}%; z-index: ${e.zIndex};">
<strong>${e.title}</strong><br>${e.time}
</div>`
)
.join("");
document.getElementById("events").innerHTML = eventHTML;
}
to12HourFormat(hour) {
if (hour === 0) return "12 AM";
if (hour < 12) return `${hour} AM`;
if (hour === 12) return "12 PM";
return `${hour - 12} PM`;
}
}
3. Обработка перекрытий событий и позиционирование
Нам нужна логика для обработки перекрывающихся событий. Это достигается путем группировки и расчета соответствующих позиций.
Группировка событий по начальному часу
groupEvents(data) {
let groups = [];
data.forEach((event) => {
let hour = parseInt(event.start.split(":")[0], 10);
if (!groups[hour]) groups[hour] = [];
groups[hour].push(event);
});
return groups;
}
Рассчет стилей событий
Для каждой группы рассчитайте значения top
, height
, width
и left
на основе времени и перекрытия.
calculateEventStyles(groups) {
let eventData = [];
groups.forEach((group) => {
let columns = [];
group.forEach((event) => {
let { start, end } = event;
let [sh, sm] = start.split(":").map(Number);
let [eh, em] = end.split(":").map(Number);
let top = sh * 60 + sm; // Convert start time to minutes
let height = (eh * 60 + em) - top; // Calculate duration in minutes
let left = columns.findIndex((col) => col.end <= start);
if (left === -1) {
left = columns.length;
columns.push({ end });
} else {
columns[left].end = end;
}
eventData.push({
title: event.name,
time: `${this.to12HourFormat(sh)} - ${this.to12HourFormat(eh)}`,
top,
height,
left: (left * 100) / columns.length,
width: 100 / columns.length,
zIndex: left,
});
});
});
return eventData;
}
4. Пример данных и инициализация
Определите ваши данные событий и инициализируйте Calendar
:
const events = [
{ name: "Meeting with Donna", start: "09:00", end: "10:30" },
{ name: "Project Sync", start: "10:00", end: "11:00" },
{ name: "Lunch Break", start: "12:00", end: "13:00" },
{ name: "Client Call", start: "11:30", end: "12:30" },
];
new Calendar(events);
5. Полный пример кода
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Calendar Component</title>
</head>
<body>
<div class="calendar">
<div class="calendar-time">
<ul id="timelist" class="calendar-timelist"></ul>
</div>
<div id="events" class="calendar-events"></div>
</div>
<script src="script.js"></script>
</body>
</html>
Заключение
Этот подход использует обычный JavaScript для динамического создания компонента, похожего на Google Календарь. Разбивая задачу на этапы рендеринга времени, группировки событий и расчета стилей, вы можете создать масштабируемые интерактивные компоненты. Вы можете экспериментировать с кодом, добавляя функции, такие как перетаскивание событий или дополнительное оформление!
Source:
https://dzone.com/articles/building-a-google-calendar-like-component-using-javascript