В проектах, где Slim Sel ect используется на десятках или сотнях элементов формы, повторяющиеся конфигурации быстро превращаются в источник дублирования и рассинхронизации поведения. Переиспользование конфигураций позволяет унифицировать и централизовать логику инициализации, снижая количество точечных ошибок и упрощая сопровождение.
Ключевая идея заключается в разделении конфигурации на базовые слои: общий набор параметров, доменные пресеты и локальные переопределения для конкретных инстансов.
Наиболее простой способ переиспользования — выделение общего объекта настроек, который используется как основа для всех экземпляров Slim Select.
const baseSelectConfig = {
placeholder: 'Выберите значение',
allowDeselect: true,
searchText: 'Поиск...',
searchPlaceholder: 'Введите текст',
searchHighlight: true,
};
При инициализации каждого нового селекта этот объект используется как шаблон:
new SlimSelect({
select: '#city-select',
...baseSelectConfig,
});
Такой подход эффективен только на начальном этапе, поскольку не учитывает необходимость изоляции и динамического расширения конфигураций.
Простое распространение через spread-оператор создаёт поверхностную
копию. Это становится проблемой при наличии вложенных объектов
конфигурации, например при использовании ajax,
data или кастомных render функций.
const config = {
ajax: {
url: '/api/cities',
delay: 300,
},
};
При повторном использовании без глубокой копии возможны ситуации, когда один экземпляр изменяет общий объект.
Решение заключается в использовании фабрик конфигураций.
Функция-фабрика позволяет генерировать новый объект конфигурации для каждого экземпляра, гарантируя изоляцию состояния.
function createBaseConfig() {
return {
placeholder: 'Выберите значение',
allowDeselect: true,
searchText: 'Поиск...',
searchPlaceholder: 'Введите текст',
searchHighlight: true,
ajax: {
delay: 250,
},
};
}
Использование:
new SlimSelect({
select: '#country-select',
...createBaseConfig(),
});
Фабрика становится особенно полезной при наличии параметров окружения или зависимости от контекста.
Следующий уровень абстракции — фабрики, принимающие аргументы и адаптирующие конфигурацию под конкретный сценарий.
function createSelectConfig(type) {
const base = {
allowDeselect: true,
searchHighlight: true,
};
if (type === 'city') {
return {
...base,
placeholder: 'Город',
searchPlaceholder: 'Найти город',
ajax: {
url: '/api/cities',
delay: 200,
},
};
}
if (type === 'country') {
return {
...base,
placeholder: 'Страна',
searchPlaceholder: 'Найти страну',
ajax: {
url: '/api/countries',
delay: 300,
},
};
}
return base;
}
Такой подход вводит концепцию конфигурационных профилей, где каждый тип компонента описывается декларативно.
При росте приложения целесообразно выделить фиксированные пресеты конфигураций, которые выступают как единицы повторного использования.
const SelectPresets = {
default: {
allowDeselect: true,
searchHighlight: true,
placeholder: 'Выберите...',
},
searchOnly: {
searchHighlight: true,
allowDeselect: false,
},
ajaxFast: {
search: true,
ajax: {
delay: 150,
},
},
};
Использование пресетов:
new SlimSelect({
select: '#product-select',
...SelectPresets.ajaxFast,
ajax: {
url: '/api/products',
...SelectPresets.ajaxFast.ajax,
},
});
Ключевой момент — аккуратное объединение вложенных структур, чтобы не терять параметры при расширении.
При наличии сложных пресетов требуется глубокое слияние объектов. Использование простого spread-оператора становится недостаточным.
function deepMerge(target, source) {
const output = { ...target };
for (const key in source) {
if (
source[key] &&
typeof source[key] === 'object' &&
!Array.isArray(source[key])
) {
output[key] = deepMerge(output[key] || {}, source[key]);
} else {
output[key] = source[key];
}
}
return output;
}
Применение:
const config = deepMerge(SelectPresets.default, {
ajax: {
url: '/api/users',
},
});
Это позволяет безопасно комбинировать базовые конфигурации и локальные модификации без потери вложенных параметров.
При росте системы часто возникает необходимость комбинировать несколько пресетов одновременно. Например, базовое поведение + AJAX + кастомный рендер.
const SelectMixins = {
ajax: {
search: true,
ajax: {
delay: 250,
},
},
compact: {
showSearch: false,
allowDeselect: false,
},
};
Композиция:
const config = deepMerge(
SelectPresets.default,
SelectMixins.ajax,
SelectMixins.compact,
{
ajax: {
url: '/api/data',
},
}
);
Такой подход формирует систему конфигураций, напоминающую CSS-модификаторы по принципу каскада.
Ещё один способ переиспользования — хранение конфигураций прямо в DOM через data-атрибуты.
<select id="city-select"
data-placeholder="Город"
data-ajax-url="/api/cities"
data-ajax-delay="200">
</select>
Парсинг:
function configFromDataset(element) {
return {
placeholder: element.dataset.placeholder,
ajax: {
url: element.dataset.ajaxUrl,
delay: Number(element.dataset.ajaxDelay),
},
};
}
new SlimSelect({
select: '#city-select',
...configFromDataset(document.querySelector('#city-select')),
});
Этот подход переносит часть конфигурации в разметку, облегчая повторное использование компонентов без изменения JavaScript-кода.
В системах с единым стилем интерфейса часто вводится глобальный слой конфигурации, применяемый ко всем экземплярам Slim Select.
const GlobalSelectDefaults = {
searchHighlight: true,
allowDeselect: true,
placeholder: 'Выберите значение',
};
Далее каждая локальная конфигурация наследует глобальные значения:
const config = deepMerge(GlobalSelectDefaults, {
placeholder: 'Страна',
});
Важно, что глобальные настройки должны оставаться неизменяемыми во время выполнения приложения, иначе нарушается предсказуемость поведения компонентов.
При масштабировании приложения конфигурации целесообразно выносить в отдельные модули, разделённые по доменам.
/config/select/
base.js
user.js
location.js
product.js
Пример модуля:
export const userSelectConfig = {
placeholder: 'Пользователь',
ajax: {
url: '/api/users',
delay: 250,
},
};
Использование:
import { userSelectConfig } fr om './config/select/user.js';
new SlimSelect({
select: '#user-select',
...userSelectConfig,
});
Такое разбиение делает конфигурации частью архитектуры приложения, а не локальной логикой UI.
Более гибкий способ — использование функций, возвращающих модифицированные конфигурации.
const withAjax = (config, url) => ({
...config,
ajax: {
...(config.ajax || {}),
url,
},
});
const withPlaceholder = (config, text) => ({
...config,
placeholder: text,
});
Композиция:
const config = withPlaceholder(
withAjax(SelectPresets.default, '/api/tags'),
'Теги'
);
Этот подход формирует декларативную цепочку преобразований, где конфигурация становится неизменяемым объектом, проходящим через набор трансформеров.
При частой инициализации одинаковых типов Slim Select имеет смысл кэшировать уже собранные конфигурации.
const configCache = new Map();
function getSelectConfig(type) {
if (configCache.has(type)) {
return configCache.get(type);
}
const config = createSelectConfig(type);
configCache.set(type, config);
return config;
}
Это уменьшает накладные расходы на сборку конфигураций при массовом рендеринге форм.
В зрелых системах конфигурации Slim Select перестают быть локальной деталью и становятся частью архитектуры состояния интерфейса. Они управляются так же, как данные приложения: через модули, композицию и изоляцию побочных эффектов.
Переиспользование конфигураций в таком подходе превращается из техники устранения дублирования в механизм стандартизации поведения UI-компонентов.