Библиотека Pikaday изначально ориентирована на выбор одной даты, однако на практике часто используется расширенная модель с диапазоном дат, реализуемая через два экземпляра календаря или через дополнительную логику поверх одного компонента. В такой конфигурации диапазон обычно представлен парой значений:
startDate — начало интервалаendDate — конец интервалаПри этом сами экземпляры Pikaday не хранят «диапазон» как сущность. Это означает, что очистка диапазона всегда сводится к управлению внешним состоянием и синхронизации нескольких источников данных: инстансов календаря, input-полей и вспомогательных переменных.
Ключевой особенностью становится необходимость учитывать не только
визуальное состояние, но и внутренние ограничения (minDate / maxDate), а
также возможные побочные эффекты событий onSelect.
Типичная реализация диапазона строится вокруг двух инстансов:
const startPicker = new Pikaday({
field: document.getElementById('start'),
onSelect: function(date) {
range.start = date;
syncRange();
}
});
const endPicker = new Pikaday({
field: document.getElementById('end'),
onSelect: function(date) {
range.end = date;
syncRange();
}
});
const range = {
start: null,
end: null
};
Очистка диапазона в такой архитектуре означает приведение к начальному состоянию:
range.start и range.endСуществует несколько устойчивых подходов к очистке диапазона дат в Pikaday-реализациях.
Наиболее прямолинейный способ — ручное обнуление всех связанных значений:
function clearRange() {
range.start = null;
range.end = null;
document.getElementById('start').value = '';
document.getElementById('end').value = '';
startPicker.setDate(null);
endPicker.setDate(null);
}
В этом случае важно учитывать, что setDate(null)
используется как способ очистки текущего значения календаря. В некоторых
реализациях Pikaday это приводит к сбросу выбранной даты, однако
визуальное поведение может зависеть от версии и кастомизаций.
В сложных интерфейсах применяется радикальный способ — уничтожение и пересоздание календарей:
function resetPickers() {
startPicker.destroy();
endPicker.destroy();
initializePickers();
}
Этот подход используется, когда:
Минусом является потеря текущих подписок и необходимость восстановления всех конфигураций.
В диапазонных интерфейсах очистка редко ограничивается только удалением дат. Обычно требуется сброс зависимостей между календарями.
При выборе диапазона часто применяется динамическая блокировка дат:
startPicker.setMaxDate(null);
endPicker.setMinDate(null);
После очистки диапазона эти ограничения должны быть сняты, иначе следующий выбор будет ограничен предыдущими значениями.
Корректная последовательность:
function clearRange() {
range.start = null;
range.end = null;
startPicker.setDate(null);
endPicker.setDate(null);
startPicker.setMaxDate(null);
endPicker.setMinDate(null);
startPicker.gotoToday();
endPicker.gotoToday();
}
Метод gotoToday() используется для возврата календаря в
нейтральное состояние отображения, предотвращая визуальную «залипшую»
навигацию на старых месяцах.
В некоторых интерфейсах допускается частичная очистка, например сброс только конца диапазона при сохранении начала.
function clearEnd() {
range.end = null;
endPicker.setDate(null);
startPicker.setMaxDate(null);
}
Это важно в сценариях, где:
function clearStart() {
range.start = null;
startPicker.setDate(null);
endPicker.setMinDate(null);
}
Такой подход часто используется в интерфейсах бронирования, где логика предполагает обязательный выбор начала перед концом.
Одной из проблем является автоматическое срабатывание
onSelect после программного изменения даты. При очистке это
может привести к нежелательным повторным вычислениям диапазона.
let isClearing = false;
function clearRange() {
isClearing = true;
range.start = null;
range.end = null;
startPicker.setDate(null);
endPicker.setDate(null);
isClearing = false;
}
И в обработчиках:
onSelect: function(date) {
if (isClearing) return;
range.start = date;
syncRange();
}
Такой механизм предотвращает каскадное обновление состояния.
Если диапазон визуально подсвечивается через CSS-классы, очистка должна затрагивать DOM-слой.
function updateHighlight() {
const cells = document.querySelectorAll('.pika-day');
cells.forEach(cell => {
cell.classList.remove('is-in-range');
cell.classList.remove('is-range-start');
cell.classList.remove('is-range-end');
});
}
function clearHighlight() {
updateHighlight();
}
В более сложных реализациях очистка выполняется через перерисовку календаря:
startPicker.draw();
endPicker.draw();
Даже при корректном сбросе Pikaday-инстансов остаётся проблема синхронизации текстовых полей.
function clearInputs() {
document.getElementById('start').value = '';
document.getElementById('end').value = '';
}
При форматировании дат через кастомный toString или
moment/dayjs-адаптер важно также сбрасывать форматированные значения,
иначе визуально поле может оставаться заполненным.
На практике удобнее централизовать очистку диапазона в одном контроллере:
const rangeController = {
clear() {
this.state = { start: null, end: null };
startPicker.setDate(null);
endPicker.setDate(null);
startPicker.setMinDate(null);
startPicker.setMaxDate(null);
endPicker.setMinDate(null);
endPicker.setMaxDate(null);
document.getElementById('start').value = '';
document.getElementById('end').value = '';
startPicker.draw();
endPicker.draw();
},
state: {
start: null,
end: null
}
};
Такой подход уменьшает риск частичных очисток и несогласованного состояния между календарями.
В реальных интерфейсах очистка часто привязана к внешним триггерам:
Пример:
document.getElementById('reset').addEventListener('click', () => {
rangeController.clear();
});
Важно учитывать, что очистка должна быть синхронной относительно UI, иначе возможны промежуточные состояния, где один календарь уже сброшен, а второй ещё нет.
Типичная проблема возникает, когда:
startDate есть, endDate отсутствуетОчистка в таких случаях должна нормализовать состояние:
function normalizeBeforeClear() {
if (range.start && range.end && range.start > range.end) {
range.end = null;
}
}
После нормализации выполняется стандартный сброс.
Pikaday сохраняет текущий отображаемый месяц. После очистки диапазона это может приводить к визуальной «задержке» старого контекста.
function resetView() {
startPicker.gotoToday();
endPicker.gotoToday();
}
В некоторых интерфейсах вместо текущей даты используется фиксированная точка:
startPicker.gotoDate(new Date());
Обобщённая последовательность очистки в диапазонной реализации:
function clearDateRange() {
range.start = null;
range.end = null;
startPicker.setDate(null);
endPicker.setDate(null);
startPicker.setMinDate(null);
startPicker.setMaxDate(null);
endPicker.setMinDate(null);
endPicker.setMaxDate(null);
document.getElementById('start').value = '';
document.getElementById('end').value = '';
startPicker.draw();
endPicker.draw();
}
Эта структура покрывает: