Ограничение диапазонов дат в Pikaday реализуется через набор встроенных параметров и расширяемых функций фильтрации, позволяющих управлять как глобальными границами выбора, так и точечными исключениями отдельных дат или периодов. Механизм ограничений влияет на логику навигации календаря, доступность ячеек и поведение пользовательского ввода.
Базовый уровень ограничения формируется двумя параметрами:
minDate и maxDate. Они задают нижнюю и верхнюю
границу допустимого выбора.
var picker = new Pikaday({
field: document.getElementById('date'),
minDate: new Date(2024, 0, 1),
maxDate: new Date(2024, 11, 31)
});
В рамках этих ограничений календарь автоматически блокирует:
Важно, что minDate и maxDate работают на
уровне сравнения объектов Date, поэтому критичным
становится единообразие временной зоны и отсутствие скрытых смещений
времени внутри логики приложения.
Pikaday допускает изменение ограничений после инициализации экземпляра. Это особенно важно при связке нескольких календарей или зависимых фильтров.
picker.setMinDate(new Date(2024, 2, 1));
picker.setMaxDate(new Date(2024, 9, 1));
При изменении границ происходит перерасчёт доступных ячеек текущего
месяца. Если выбранная дата выходит за новый диапазон, она не всегда
автоматически сбрасывается, поэтому требуется дополнительная проверка
состояния getDate().
Типичный сценарий — фильтрация данных в зависимости от выбора пользователя (например, выбор периода отчёта, где границы зависят от сервера или другого поля формы).
Более гибкий механизм ограничений реализуется через функцию
disableFn, которая вызывается для каждой даты при
построении календаря.
var picker = new Pikaday({
field: document.getElementById('date'),
disableFn: function(date) {
return date.getDay() === 0 || date.getDay() === 6;
}
});
Если функция возвращает true, дата становится
недоступной для выбора. Такой подход позволяет реализовать:
Особенность disableFn заключается в том, что она
применяется поверх minDate и maxDate, то есть
итоговая доступность определяется совокупностью всех ограничений.
Для статических ограничений используется массив дат, проверяемый
внутри disableFn или вспомогательной логики.
var disabledDates = [
new Date(2024, 5, 10),
new Date(2024, 5, 11),
new Date(2024, 5, 12)
];
var picker = new Pikaday({
field: document.getElementById('date'),
disableFn: function(date) {
return disabledDates.some(function(d) {
return d.getTime() === date.getTime();
});
}
});
Сравнение через getTime() обеспечивает точное
сопоставление, исключая проблемы с объектной идентичностью
Date.
При больших списках применяется оптимизация через Set
или нормализацию даты до полуночи, чтобы уменьшить стоимость поиска.
Помимо отдельных значений, часто требуется исключать целые периоды. Это реализуется проверкой попадания даты в интервал.
function isInRange(date, start, end) {
return date >= start && date <= end;
}
var picker = new Pikaday({
field: document.getElementById('date'),
disableFn: function(date) {
return isInRange(date,
new Date(2024, 3, 1),
new Date(2024, 3, 15)
);
}
});
Такой подход используется для:
При работе с диапазонами важно учитывать включительность границ,
поскольку стандартное сравнение >= и <=
делает диапазон инклюзивным.
Часто Pikaday применяется в паре для выбора начальной и конечной даты периода. В таком случае ограничения становятся динамическими и зависят от состояния второго календаря.
var startPicker = new Pikaday({
field: document.getElementById('start'),
onSelect: function(date) {
endPicker.setMinDate(date);
}
});
var endPicker = new Pikaday({
field: document.getElementById('end'),
onSelect: function(date) {
startPicker.setMaxDate(date);
}
});
Такая связка обеспечивает инвариант:
При этом логика ограничений распределяется между двумя экземплярами, что снижает необходимость централизованной валидации формы.
Ограничения интерфейса не заменяют проверку данных. Значение может быть установлено программно, минуя UI-фильтры.
var date = picker.getDate();
if (date < minAllowed || date > maxAllowed) {
picker.setDate(null);
}
Особое внимание уделяется случаям, когда:
Pikaday ориентирован на работу с датами без явного времени, однако
объект Date всегда содержит временную часть. Это создаёт
потенциальные расхождения при сравнении.
Для стабильности применяется нормализация:
function normalize(date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
Без такой нормализации возможно некорректное поведение при сравнении
minDate, maxDate и пользовательских значений,
особенно при работе с часовыми поясами.
Реальная логика ограничений почти всегда включает несколько уровней:
minDate,
maxDate);disableFn);Итоговая доступность даты определяется как пересечение всех условий:
дата допустима ⇔
дата ∈ [minDate, maxDate] ∧
disableFn(date) = false ∧
не входит в запрещённые диапазоны
Такой подход позволяет строить сложные сценарии выбора дат без модификации внутренней логики библиотеки.
При увеличении числа проверок критичным становится порядок выполнения условий. Оптимизация обычно строится по принципу раннего выхода:
disableFn: function(date) {
if (date < minBoundary || date > maxBoundary) return true;
if (isWeekend(date)) return true;
if (disabledSet.has(date.getTime())) return true;
return false;
}
Сначала проверяются дешёвые условия, затем более затратные операции поиска.
Когда значительная часть диапазона недоступна, календарь продолжает отображать все дни месяца, но визуально маркирует их как disabled. Навигация по месяцам также может блокироваться, если следующий или предыдущий месяц полностью выходит за допустимые границы.
В таких условиях важно, что пользовательский ввод через поле может оставаться активным, поэтому логика ограничений должна дублироваться на уровне валидации формы и бизнес-слоя приложения.