Структура событий

Библиотека Pikaday построена вокруг событийной модели, позволяющей отслеживать ключевые этапы взаимодействия пользователя с календарём. События формируют основной механизм интеграции datepicker в бизнес-логику приложения: через них осуществляется синхронизация состояния, валидация дат, обновление интерфейса и управление связанными компонентами.

Событийная структура в Pikaday делится на две категории: жизненный цикл экземпляра календаря и события выбора/изменения даты. Каждая категория отражает отдельный слой поведения компонента и имеет собственные точки расширения.


Общая модель событий

Pikaday не использует сложную систему кастомного EventEmitter, как в крупных фреймворках. Вместо этого применяется простая модель: колбэки передаются в конфигурации экземпляра и вызываются в строго определённые моменты жизненного цикла.

Ключевая особенность:

  • события задаются через опции конструктора
  • каждый callback связан с конкретным действием
  • порядок вызова детерминирован

Пример общей структуры инициализации:

const picker = new Pikaday({
    field: document.getElementById('input'),
    onSelect: function(date) {
        console.log(date);
    },
    onOpen: function() {},
    onClose: function() {},
    onDraw: function() {}
});

Событие выбора даты (onSelect)

Назначение

onSelect — центральное событие библиотеки. Оно срабатывает при выборе даты пользователем или при установке даты программно через API.

Поведение

Событие вызывается:

  • при клике по дню в календаре
  • при вызове setDate
  • при изменении диапазона (если используется расширенная логика)

Передаваемые данные

В callback передаётся:

  • объект Date (выбранная дата)
onSelect: function(date) {
    console.log(date.toISOString());
}

Особенности

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

Событие открытия календаря (onOpen)

Назначение

onOpen вызывается в момент, когда календарь становится видимым.

Триггеры

  • фокус на поле ввода
  • программный вызов show()
  • переключение состояния isVisible → true

Поведение

onOpen: function() {
    console.log('Календарь открыт');
}

Событие не принимает параметров, так как состояние экземпляра уже доступно через API объекта.

Важные особенности

  • вызывается только при переходе из скрытого состояния
  • не срабатывает при повторной инициализации без скрытия
  • часто используется для ленивой подгрузки данных (например, отключённых дат)

Событие закрытия календаря (onClose)

Назначение

onClose срабатывает при скрытии календаря и завершении взаимодействия с ним.

Триггеры

  • потеря фокуса полем ввода
  • клик вне области календаря
  • вызов hide()

Пример

onClose: function() {
    console.log('Календарь закрыт');
}

Особенности поведения

  • вызывается после завершения анимации (если она реализована кастомно)
  • гарантирует, что DOM календаря уже скрыт
  • используется для очистки временных состояний интерфейса

Событие отрисовки (onDraw)

Назначение

onDraw вызывается при каждом рендере календарной сетки.

Когда срабатывает

  • при первом отображении
  • при переключении месяца
  • при смене года
  • при изменении min/max дат
  • при программной навигации (gotoMonth, gotoYear)

Пример использования

onDraw: function() {
    console.log('Календарь перерисован');
}

Особенности

  • не получает параметров
  • может вызываться часто, особенно при навигации
  • требует осторожного использования для тяжёлых операций

Влияние на производительность

Поскольку onDraw может срабатывать многократно в короткий промежуток времени, внутри него не рекомендуется выполнять:

  • DOM-манипуляции высокой стоимости
  • запросы к серверу
  • сложные вычисления

Событие изменения значения через API

Хотя Pikaday не выделяет отдельное событие для всех программных изменений, такие изменения всё равно проходят через onSelect.

Ключевые методы, инициирующие событие:

  • setDate(date)
  • setMoment(moment) (если используется Moment.js интеграция)
  • gotoDate(date) (не всегда вызывает onSelect, зависит от реализации)

Порядок вызова событий

При выборе даты через интерфейс последовательность событий обычно выглядит следующим образом:

  1. обработка клика по ячейке календаря
  2. обновление внутреннего состояния
  3. вызов onSelect
  4. возможная перерисовка (onDraw)
  5. сохранение значения в input
  6. закрытие календаря (если включено autoClose)
  7. вызов onClose

При открытии:

  1. изменение состояния видимости
  2. инициализация DOM (если требуется)
  3. вызов onDraw
  4. вызов onOpen

Связь событий с состоянием экземпляра

Каждое событие тесно связано с внутренними полями объекта календаря:

  • isVisibleonOpen, onClose
  • currentDateonSelect
  • viewDateonDraw

Состояние экземпляра обновляется до вызова колбэков, что гарантирует консистентность данных внутри обработчиков.


Программное управление и события

При работе через API важно учитывать различие между пользовательскими и программными изменениями.

setDate

picker.setDate(new Date());
  • вызывает onSelect
  • может вызвать onDraw
  • обновляет input

gotoMonth / gotoYear

picker.gotoMonth(5);
  • вызывает onDraw
  • не вызывает onSelect

Особенности архитектуры событий

Система событий Pikaday построена на принципах:

  • минимализм API
  • отсутствие централизованного event bus
  • жёсткая привязка callback → действие
  • синхронное выполнение обработчиков

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


Типичные сценарии использования событий

Синхронизация с внешними формами

onSelect используется для обновления связанных полей:

onSelect: function(date) {
    hiddenInput.value = date.toISOString();
}

Управление доступностью интерфейса

onOpen: function() {
    overlay.classList.add('active');
}

Динамическое обновление ограничений

onDraw: function() {
    updateDisabledDays();
}

Ограничения событийной модели

  • отсутствует система отмены события (no preventDefault)
  • нет асинхронных хуков
  • нельзя перехватывать внутренние переходы состояния
  • порядок вызовов фиксирован и не настраивается

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