Сохранение состояния выпадающих списков, созданных на базе Slim
Select, позволяет восстанавливать выбор пользователя после перезагрузки
страницы, переходов между разделами и повторного открытия интерфейса.
Основной механизм основан на синхронизации выбранных значений с
localStorage и последующем восстановлении состояния при
инициализации компонента.
Slim Select работает поверх стандартного <select>
элемента, поэтому состояние фактически сводится к набору выбранных
value. Эти значения удобно сериализовать в строку и
сохранять в браузере.
Ключевой принцип:
localStorageПростейшая схема хранения:
const STORAGE_KEY = 'slimselect:country';
function saveState(values) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(values));
}
function loadState() {
const raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : [];
}
При создании экземпляра Slim Select важно учитывать момент, когда
значения уже восстановлены из localStorage. Обычно
восстановление выполняется до или сразу после инициализации.
const selectEl = document.querySelector('#country');
const savedValues = loadState();
const slim = new SlimSelect({
select: selectEl
});
if (savedValues.length) {
slim.set(savedValues);
}
Метод set позволяет программно задать выбранные
значения, что делает его ключевым элементом восстановления
состояния.
Для постоянного обновления состояния используется событие изменения
выбора. Slim Select предоставляет callback onChange,
который вызывается при каждом изменении значения.
const slim = new SlimSelect({
select: '#country',
onChange: (info) => {
const values = info.map(item => item.value);
saveState(values);
}
});
Здесь info содержит массив выбранных элементов, каждый
из которых включает value, text и
дополнительные метаданные.
Поведение сохранения зависит от режима multiple.
В случае обычного <select> сохраняется одно
значение:
onChange: (info) => {
const value = info ? info.value : null;
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
}
Восстановление:
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
if (saved) {
slim.set(saved);
}
При multiple сохраняется массив:
onChange: (info) => {
const values = info.map(i => i.value);
localStorage.setItem(STORAGE_KEY, JSON.stringify(values));
}
Восстановление аналогично:
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
slim.set(saved);
При работе с несколькими экземплярами Slim Select важно использовать уникальные ключи хранения, иначе состояния будут перезаписываться.
const STORAGE_KEYS = {
country: 'slimselect:country',
city: 'slimselect:city',
language: 'slimselect:language'
};
Инициализация каждого селекта:
function createPersistedSelect(selector, key) {
const slim = new SlimSelect({
select: selector,
onChange: (info) => {
const values = Array.isArray(info)
? info.map(i => i.value)
: info?.value;
localStorage.setItem(key, JSON.stringify(values));
}
});
const saved = JSON.parse(localStorage.getItem(key) || 'null');
if (saved) {
slim.set(saved);
}
return slim;
}
createPersistedSelect('#country', STORAGE_KEYS.country);
createPersistedSelect('#city', STORAGE_KEYS.city);
Если список опций загружается асинхронно (например, через API), восстановление состояния должно выполняться после загрузки данных, иначе Slim Select не сможет сопоставить значения.
const slim = new SlimSelect({
select: '#country',
data: []
});
fetch('/api/countries')
.then(res => res.json())
.then(options => {
slim.setData(options);
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
slim.set(saved);
});
Здесь критически важно соблюдать порядок:
setDatasetЕсли значения представляют собой не строки, а объекты (например,
{ id, name }), хранить в localStorage
приходится только идентификаторы.
onChange: (info) => {
const ids = info.map(i => i.value.id);
localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
}
При восстановлении требуется сопоставление:
const savedIds = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
const matched = options.filter(opt =>
savedIds.includes(opt.value.id)
);
slim.set(matched.map(m => m.value));
При необходимости сброса выбора используется удаление ключа из
localStorage и очистка Slim Select.
localStorage.removeItem(STORAGE_KEY);
slim.set([]);
Дополнительно возможно принудительное обновление UI:
slim.setData(slim.data);
slim.set([]);
При изменении структуры данных (например, переход с
string на объект) старые значения могут стать
несовместимыми. Для предотвращения конфликтов используется версия
ключа.
const STORAGE_KEY = 'slimselect:country:v2';
Или более гибкий вариант:
const STORAGE_KEY = `slimselect:country:${APP_VERSION}`;
При смене версии старые данные автоматически игнорируются.
localStorage может содержать повреждённые данные,
поэтому требуется безопасный парсинг.
function safeLoad(key) {
try {
return JSON.parse(localStorage.getItem(key)) || [];
} catch (e) {
return [];
}
}
Использование:
const saved = safeLoad(STORAGE_KEY);
slim.set(saved);
Если сохранённые значения отсутствуют в текущем списке опций, Slim Select игнорирует их. Это важно учитывать при фильтрации данных с сервера.
Практика обработки:
const validValues = saved.filter(v =>
options.some(opt => opt.value === v)
);
slim.set(validValues);
При использовании Slim Select внутри формы важно синхронизировать
localStorage с отправкой формы, чтобы не возникало
расхождений между UI и отправляемыми данными.
form.addEventListener('submit', () => {
const values = slim.selected();
localStorage.setItem(STORAGE_KEY, JSON.stringify(values));
});
Дополнительно возможно восстановление состояния при возврате на страницу без повторной загрузки данных.
При частых изменениях выбора (особенно в режиме
multiple) запись в localStorage может
выполняться слишком часто. Используется простое ограничение через
debounce.
let timeout;
function debounceSave(values) {
clearTimeout(timeout);
timeout = setTimeout(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(values));
}, 200);
}
Использование:
onChange: (info) => {
const values = info.map(i => i.value);
debounceSave(values);
}
localStorage не синхронизирует изменения автоматически
между вкладками. Для этого используется событие
storage.
window.addEventListener('storage', (e) => {
if (e.key === STORAGE_KEY) {
const values = JSON.parse(e.newValue || '[]');
slim.set(values);
}
});
Это позволяет поддерживать единое состояние интерфейса в разных вкладках браузера.