Сохранение состояния в localStorage

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

Базовый принцип хранения даты

Pikaday оперирует объектами Date, однако localStorage поддерживает только строковый формат. Поэтому выбранная дата преобразуется в сериализованный вид перед сохранением и обратно восстанавливается при загрузке.

Наиболее устойчивыми форматами считаются:

  • ISO-строка (YYYY-MM-DDTHH:mm:ss.sssZ)
  • UNIX timestamp (число миллисекунд)
  • формат YYYY-MM-DD для упрощённых сценариев

Практика показывает, что ISO-строка обеспечивает лучшую совместимость при восстановлении через new Date().


Сохранение выбранной даты через onSelect

Pikaday предоставляет хук onSelect, который вызывается при выборе даты. Именно в этом месте удобно синхронизировать состояние с localStorage.

const picker = new Pikaday({
    field: document.getElementById('date-input'),
    onSelect: function(date) {
        const isoDate = date.toISOString();
        localStorage.setItem('selectedDate', isoDate);
    }
});

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


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

При повторной загрузке страницы необходимо проверить наличие сохранённого значения и передать его в Pikaday через метод setDate.

const savedDate = localStorage.getItem('selectedDate');

const picker = new Pikaday({
    field: document.getElementById('date-input'),
    onSelect: function(date) {
        localStorage.setItem('selectedDate', date.toISOString());
    }
});

if (savedDate) {
    const parsedDate = new Date(savedDate);
    picker.setDate(parsedDate);
}

Такой подход обеспечивает синхронное восстановление UI календаря и значения в поле ввода.


Использование формата YYYY-MM-DD

В случаях, когда время не имеет значения, более удобным является хранение даты без временной составляющей.

function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

function parseDate(str) {
    const [year, month, day] = str.split('-').map(Number);
    return new Date(year, month - 1, day);
}

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

const picker = new Pikaday({
    field: document.getElementById('date-input'),
    onSelect: function(date) {
        localStorage.setItem('selectedDate', formatDate(date));
    }
});

const saved = localStorage.getItem('selectedDate');
if (saved) {
    picker.setDate(parseDate(saved));
}

Обработка отсутствующих значений

При отсутствии сохранённого состояния необходимо избегать передачи некорректных значений в setDate. Pikaday ожидает либо валидный объект Date, либо null.

const saved = localStorage.getItem('selectedDate');

if (saved !== null) {
    const date = new Date(saved);
    if (!isNaN(date.getTime())) {
        picker.setDate(date);
    }
}

Проверка валидности даты предотвращает появление некорректного состояния интерфейса.


Синхронизация нескольких полей календаря

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

function bindPicker(picker, storageKey) {
    picker.onSel ect = function(date) {
        localStorage.setItem(storageKey, date.toISOString());
    };

    const saved = localStorage.getItem(storageKey);
    if (saved) {
        picker.setDate(new Date(saved));
    }
}

Применение:

const startPicker = new Pikaday({
    field: document.getElementById('start')
});

const endPicker = new Pikaday({
    field: document.getElementById('end')
});

bindPicker(startPicker, 'startDate');
bindPicker(endPicker, 'endDate');

Такой подход обеспечивает независимое хранение состояний для каждого поля.


Хранение диапазона дат

При реализации выбора диапазона необходимо сохранять два значения: начало и конец периода.

function saveRange(start, end) {
    localStorage.setItem('rangeStart', start ? start.toISOString() : '');
    localStorage.setItem('rangeEnd', end ? end.toISOString() : '');
}

Восстановление:

const start = localStorage.getItem('rangeStart');
const end = localStorage.getItem('rangeEnd');

if (start) pickerStart.setDate(new Date(start));
if (end) pickerEnd.setDate(new Date(end));

Важно учитывать пустые значения, которые обозначают отсутствие выбранной границы.


Очистка сохранённого состояния

При необходимости сброса календаря и локального состояния используется удаление ключей из localStorage.

localStorage.removeItem('selectedDate');
picker.setDate(null);

В сценариях с диапазоном:

localStorage.removeItem('rangeStart');
localStorage.removeItem('rangeEnd');

После очистки календарь возвращается в исходное состояние без выбранных значений.


Обработка нескольких вкладок браузера

localStorage синхронизируется между вкладками через событие storage. Это позволяет обновлять Pikaday в реальном времени при изменении данных в другой вкладке.

window.addEventListener('storage', function(event) {
    if (event.key === 'selectedDate') {
        const newValue = event.newValue;
        if (newValue) {
            picker.setDate(new Date(newValue));
        } else {
            picker.setDate(null);
        }
    }
});

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


Защита от конфликтов форматов

При смешивании форматов хранения возможно возникновение ошибок парсинга. Для предотвращения этого применяется единая стратегия сериализации.

function safeParseDate(value) {
    const date = new Date(value);
    return isNaN(date.getTime()) ? null : date;
}

Использование централизованного парсера упрощает поддержку и снижает вероятность некорректного восстановления состояния.


Интеграция с пользовательскими настройками Pikaday

Pikaday поддерживает форматирование через toString и parse, что позволяет согласовать отображение и хранение данных.

const picker = new Pikaday({
    field: document.getElementById('date-input'),
    toString(date) {
        return formatDate(date);
    },
    parse(dateString) {
        return parseDate(dateString);
    },
    onSelect(date) {
        localStorage.setItem('selectedDate', formatDate(date));
    }
});

Такой подход обеспечивает единый формат на всех уровнях: отображение, хранение и восстановление.


Работа с временными зонами

При использовании ISO-строк важно учитывать влияние временной зоны. В некоторых случаях дата может смещаться при восстановлении из-за UTC-конвертации.

Альтернативный подход заключается в хранении локальной даты без времени:

function toLocalISO(date) {
    return new Date(date.getTime() - date.getTimezoneOffset() * 60000)
        .toISOString()
        .split('T')[0];
}

Этот метод фиксирует только календарную часть, исключая смещение времени.


Оптимизация записи в localStorage

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

let lastSaved = null;

picker.onSel ect = function(date) {
    const value = date.toISOString();
    if (value !== lastSaved) {
        lastSaved = value;
        localStorage.setItem('selectedDate', value);
    }
};

Такой подход снижает количество операций записи и повышает стабильность при интенсивном взаимодействии с календарём.