В библиотеке Pikaday механизм ограничения доступных дат реализуется
не только через статические параметры minDate и
maxDate, но и через функциональный подход, позволяющий
вычислять доступность каждой конкретной даты в момент её отрисовки.
Основным инструментом для этого выступает disableDayFn,
принимающий функцию-предикат, возвращающую логическое значение для
каждой проверяемой даты.
Такой подход обеспечивает динамическую модель блокировок, где логика определяется произвольными условиями: календарными правилами, бизнес-ограничениями, внешними данными или комбинированными сценариями.
При инициализации календаря каждая дата, которая должна быть отображена в сетке месяца, проходит проверку через функцию:
disableDayFn: function(date) {
return false; // дата доступна
}
Если функция возвращает true, дата считается недоступной
для выбора и визуально блокируется в интерфейсе. Если возвращается
false, дата остаётся активной.
Внутренне проверка выполняется для каждой ячейки календаря при рендеринге, что делает механизм синхронным и детерминированным.
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
return date.getDay() === 0; // блокировка воскресений
}
});
В данном случае используется метод getDay(),
возвращающий день недели (0 — воскресенье). Такой подход часто
применяется для исключения выходных или отдельных рабочих дней.
Частый сценарий — отключение суббот и воскресений:
disableDayFn: function(date) {
var day = date.getDay();
return (day === 0 || day === 6);
}
Логика предельно проста и масштабируема: добавление дополнительных условий не нарушает структуру функции.
Функциональная блокировка позволяет легко исключить все даты до текущего дня:
var today = new Date();
today.setHours(0, 0, 0, 0);
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
var normalized = new Date(date.getFullYear(), date.getMonth(), date.getDate());
return normalized < today;
}
});
Нормализация времени до полуночи предотвращает ошибки, связанные с
часовыми смещениями и сравнением объектов Date с разным
временем.
Для сценариев, где требуется запретить фиксированный список дат (например, праздничные дни или технические остановки), используется массив контрольных значений.
var blockedDates = [
'2026-01-01',
'2026-01-07',
'2026-05-09'
];
function format(date) {
var y = date.getFullYear();
var m = String(date.getMonth() + 1).padStart(2, '0');
var d = String(date.getDate()).padStart(2, '0');
return y + '-' + m + '-' + d;
}
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
return blockedDates.indexOf(format(date)) !== -1;
}
});
Такая модель удобна для интеграции с серверными API, где список недоступных дат может обновляться динамически.
Функция может включать сложные вычисления, основанные на бизнес-логике. Например, блокировка всех дат, попадающих в определённый диапазон месяцев:
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
var month = date.getMonth();
return month === 6 || month === 7; // июль и август недоступны
}
});
Такой подход часто используется для сезонных ограничений.
Функциональная природа disableDayFn позволяет объединять
несколько правил в одной точке контроля.
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
var day = date.getDay();
var isWeekend = (day === 0 || day === 6);
var today = new Date();
today.setHours(0, 0, 0, 0);
var current = new Date(date.getFullYear(), date.getMonth(), date.getDate());
var isPast = current < today;
return isWeekend || isPast;
}
});
Логика становится декларативной: каждое условие выражает отдельное ограничение, а итоговое значение формируется через логическое объединение.
В реальных приложениях данные о блокировках часто поступают извне. Это может быть ответ API, конфигурация сервера или состояние системы.
var unavailableMap = {
'2026-02-10': true,
'2026-02-11': true,
'2026-02-12': false
};
function format(date) {
return date.toISOString().slice(0, 10);
}
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
return !!unavailableMap[format(date)];
}
});
Такой подход обеспечивает синхронизацию календаря с серверной логикой без изменения клиентского кода.
Хотя Pikaday работает на уровне даты, возможно
добавление контекста времени через внешние переменные состояния.
var cutoffHour = 15; // 15:00
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
var now = new Date();
var isToday =
date.getFullYear() === now.getFullYear() &&
date.getMonth() === now.getMonth() &&
date.getDate() === now.getDate();
if (!isToday) {
return false;
}
return now.getHours() >= cutoffHour;
}
});
В результате текущий день становится недоступным после определённого времени.
minDate, maxDate и disableDayFnminDate и maxDate задают жесткие границы
диапазона, в то время как disableDayFn работает внутри этих
границ, уточняя доступность отдельных дат.
var picker = new Pikaday({
field: document.getElementById('datepicker'),
minDate: new Date(2026, 0, 1),
maxDate: new Date(2026, 11, 31),
disableDayFn: function(date) {
return date.getDay() === 1; // блокировка понедельников
}
});
Даже если дата входит в допустимый диапазон, она может быть отключена функцией.
При большом количестве условий целесообразно выносить вычисления за пределы функции рендера, чтобы уменьшить нагрузку при открытии календаря.
var cache = {};
function computeKey(date) {
return date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate();
}
var picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
var key = computeKey(date);
if (cache[key] !== undefined) {
return cache[key];
}
var result =
date.getDay() === 0 ||
date.getDay() === 6;
cache[key] = result;
return result;
}
});
Такой механизм особенно полезен при сложных проверках, включающих обращения к структурам данных или вычислительным операциям.
На практике функциональная блокировка часто комбинируется с предрасчитанными наборами дат и динамическими условиями.
var holidays = new Set(['2026-01-01', '2026-12-31']);
function format(date) {
return date.toISOString().slice(0, 10);
}
var picker = new Pikaday({
field: document.getElementById('datepicker'),
minDate: new Date(2026, 0, 1),
maxDate: new Date(2026, 11, 31),
disableDayFn: function(date) {
var isWeekend = date.getDay() === 0 || date.getDay() === 6;
var isHoliday = holidays.has(format(date));
return isWeekend || isHoliday;
}
});