form.form.form_type_default.form-search(data-form-id="search")
.form__fields
.form__field.form__field-query
label.form__label(for="form-search-field-query") Поиск
input.form__input(id="form-search-field-query", type="text", name="query", data-type="query", value="")
.form__field.form__field-result
.search-result-popover
.search-result-popover__content Содержимое поповера
.form__actions
button.form__submit.button.button-primary.button-m(type="submit")
.button__icon
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15Z" stroke="#151515" stroke-width="1.5" stroke-linejoin="round" />
<path d="M13 13L16.5 16.5" stroke="#151515" stroke-width="1.5" stroke-linejoin="round" />
</svg>
.button__name Найти
Статичный поиск - это классический вид поиска с полем для ввода и кнопкой.
.search_type_full - поле для ввода и кнопка отдельно от поля..search_type_compact - поле для ввода и кнопка поверх поля. .search.search_view_static[.search_type_full|.search_type_compact]
.search__form
include ../../components/forms/custom/search/search
Скользящий поиск - это вид поиска который отображает только иконку поиска, а поле для ввода и кнопка выезжают при наведении.
.search_type_full - поле для ввода и кнопка отдельно от поля..search_type_compact - поле для ввода и кнопка поверх поля..search_direction_left - Направление формы в какую сторону будет выезжать..search_direction_right - Направление формы в какую сторону будет выезжать. .search.search_view_sliding[.search_type_full|.search_type_compact][.search_direction_left|.search_direction_right]
.search__icon
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15Z" stroke="#151515" stroke-width="1.5" stroke-linejoin="round" />
<path d="M13 13L16.5 16.5" stroke="#151515" stroke-width="1.5" stroke-linejoin="round" />
</svg>
.search__form
include ../../components/forms/custom/search/search
new CustomSearch();
new CustomSearch({
clear: false,
placeholder: 'Поиск'
});
/**
*
* Custom Search 3.1.0
* Поиск
*
* Copyright 2025 Mihail Pridannikov
*
* Released on: July 28, 2025
*
*/
window.CustomSearch = function(customSettings) {
this.deepMergeObjects = function (obj1, obj2) {
const result = {};
for (const key in obj2) {
if (obj2.hasOwnProperty(key)) {
if (typeof obj2[key] === "object" && obj1.hasOwnProperty(key) && typeof obj1[key] === "object") {
result[key] = this.deepMergeObjects(obj1[key], obj2[key]);
} else {
result[key] = obj2[key];
}
}
}
for (const key in obj1) {
if (obj1.hasOwnProperty(key) && !result.hasOwnProperty(key)) {
if (typeof obj1[key] === "object") {
result[key] = this.deepMergeObjects(obj1[key], {});
} else {
result[key] = obj1[key];
}
}
}
return result;
}
const FORM = document.querySelectorAll('.form-search');
const DEFAULT_SETTINGS = {
mocks: true,
clear: true,
placeholder: 'Поиск',
}
let settings = this.deepMergeObjects(DEFAULT_SETTINGS, customSettings);
this.init = function () {
// console.log('default', DEFAULT_SETTINGS)
// console.log('custom', customSettings)
// console.log('merge', settings)
if (FORM.length) {
FORM.forEach(form => {
if (form) {
// добавляем кнопку очистить поле
if (form.querySelector('.form__input').value !== '') {
this.addButtonClear(form);
this.addClassFilled(form);
}
// событие при изменении поля
form.querySelector('.form__input').addEventListener('input', e => this.handlerChangeOnTextField(e, form));
this.setPlaceholder(form);
// this.setSettingsSearchInHeader(form);
}
});
window.addEventListener('resize', e => {
this.handlerResizeWindow();
}, true);
}
}
this.handlerResizeWindow = function () {
FORM.forEach(form => {
if (form) {
this.setPlaceholder(form);
// this.setSettingsSearchInHeader(form);
}
});
}
this.setPlaceholder = function (search) {
switch (typeof settings.placeholder) {
case 'string':
search.querySelector('.form__input').setAttribute('placeholder', settings.placeholder);
break;
case 'object':
let checkRange = Object.entries(settings.placeholder).find(item => document.body.classList.contains(`js-device-${item[0]}`));
search.querySelector('.form__input').setAttribute('placeholder', checkRange ? checkRange[1] : 'Поиск');
break;
default:
break;
}
}
this.handlerChangeOnTextField = function (e, form) {
// добавляем кнопку очистить поле
if (e.currentTarget.value !== '') {
this.addButtonClear(form);
this.addClassFilled(form);
this.initSearchResult(form, e.currentTarget.value.toLowerCase());
} else {
this.removeButtonClear(form);
this.removeClasses(form);
settings.mocks ? this.closePopover(form) : this.removeResults(form);
}
}
this.initSearchResult = function (form, query) {
if (settings.mocks) {
this.openPopover(form);
} else {
let words = query.split(' ');
words.filter(word => {
this.getData(form, word);
});
}
}
this.addButtonClear = function (form) {
if (settings.clear) {
if (!form.querySelector('.form__button-clear')) {
form.querySelector('.form__field-query').insertAdjacentHTML('beforeend',
`<button class="form__button-clear">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path fill="gray" d="M1.793 1.796a1 1 0 000 1.414l4.793 4.793-4.793 4.793a1 1 0 001.414 1.414L8 9.417l4.793 4.793a1 1 0 001.414-1.414L9.414 8.003l4.793-4.793a1 1 0 00-1.414-1.414L8 6.589 3.207 1.796a1 1 0 00-1.414 0z" />
</svg>
</button>`);
form.classList.add('is-button-clear');
form.querySelector('.form__button-clear').addEventListener('click', e => this.handlerClickOnButtonClear(e, form));
}
}
}
this.removeButtonClear = function (search) {
if (search.querySelector('.form__button-clear')) {
search.querySelector('.form__button-clear').remove();
search.classList.remove('is-button-clear');
}
}
this.handlerClickOnButtonClear = function (e, form) {
e.preventDefault();
form.querySelector('.form__input').value = '';
this.removeClasses(form);
settings.mocks ? this.closePopover(form) : this.removeResults(form);
this.removeButtonClear(form);
}
this.removeClasses = function (search) {
search.classList.remove('is-focus');
search.classList.remove('is-open');
search.classList.remove('is-filled');
}
this.addClassFilled = function (form) {
form.classList.add('is-filled');
}
this.createPopover = function (form, data) {
if (!form.querySelector('.form__field-result')) {
form.querySelector('.form__fields').insertAdjacentHTML('beforeend', `
<div class="form__field form__field-result">
<div class="search-result-popover">
<div class="search-result-popover__content"></div>
</div>
</div>
`);
}
const field = form.querySelector('.form__field-result');
this.clearResults(field);
this.insertResults(form, data);
}
this.openPopover = function (form) {
form.classList.add('is-popover-opened');
}
this.closePopover = function (form) {
form.classList.remove('is-popover-opened');
}
this.insertResults = function (form, data) {
if (data) {
data.map(item => {
form.querySelector('.search-result-popover__content').insertAdjacentHTML('beforeend',
`
<div class="search-result-mini__item">
<div class="teaser-product-search">
<div class="teaser-product-search__image">
<img src="" alt="" width="32" height="32" loading="lazy">
</div>
<div class="teaser-product-search__name">Тестовое название товара</div>
<div class="teaser-product-search__price">1 000р.</div>
</div>
</div>
`);
});
} else {
form.querySelector('.search-result-popover__content').textContent = 'Результаты не найдены';
}
this.openPopover(form);
}
this.clearResults = function (field) {
field.querySelector('.search-result-popover__content').innerHTML = '';
}
this.removeResults = function (form) {
if (form.querySelector('.form__field-result')) {
form.querySelector('.form__field-result').remove();
}
}
this.getData = function (form, query) {
fetch('/rest/search?key=' + query, {method: 'GET'})
.then((response) => {
if (response.ok) {
return response.json()
}
throw new Error('Network response was not ok')
})
.then((data) => {
// console.log('DATA:', data);
this.createPopover(form, data);
})
.catch((error) => {
console.log('ERROR:', error);
})
}
if (FORM) {
this.init();
}
}
new CustomSearch();
new CustomSearch({
clear: false,
placeholder: 'Поиск'
});
/**
*
* Custom Search 3.0.0
* Поиск
*
* Copyright 2025 Mihail Pridannikov
*
* Released on: July 3, 2025
*
*/
window.CustomSearch = function(customSettings) {
this.deepMergeObjects = function (obj1, obj2) {
const result = {};
for (const key in obj2) {
if (obj2.hasOwnProperty(key)) {
if (typeof obj2[key] === "object" && obj1.hasOwnProperty(key) && typeof obj1[key] === "object") {
result[key] = this.deepMergeObjects(obj1[key], obj2[key]);
} else {
result[key] = obj2[key];
}
}
}
for (const key in obj1) {
if (obj1.hasOwnProperty(key) && !result.hasOwnProperty(key)) {
if (typeof obj1[key] === "object") {
result[key] = this.deepMergeObjects(obj1[key], {});
} else {
result[key] = obj1[key];
}
}
}
return result;
}
const FORM = document.querySelectorAll('.form-search');
const DEFAULT_SETTINGS = {
clear: true,
placeholder: 'Поиск',
// placeholder: {
// desktop: 'Поиск на ПК',
// tablet: 'Поиск на планшете',
// mobile: 'Поиск на телефоне',
// 'mobile-sm': 'Поиск на маленьком телефоне',
// },
// headerType: 'full',
// headerSlideDirection: null,
// headerBreakpoint: {
// breakpoint: [767, 1023],
// type: 'short',
// slideDirection: 'left'
// }
}
let settings = this.deepMergeObjects(DEFAULT_SETTINGS, customSettings);
this.init = function () {
console.log('default', DEFAULT_SETTINGS)
console.log('custom', customSettings)
console.log('merge', settings)
if (FORM.length) {
FORM.forEach(form => {
if (form) {
// добавляем кнопку очистить поле
if (form.querySelector('.form__input').value !== '') {
this.addButtonClear(form);
this.addClassFilled(form);
}
// событие при изменении поля
form.querySelector('.form__input').addEventListener('input', e => this.handlerChangeOnTextField(e, form));
this.setPlaceholder(form);
// this.setSettingsSearchInHeader(form);
}
});
window.addEventListener('resize', e => {
this.handlerResizeWindow();
}, true);
}
}
// событие на изменение разрешения браузера
this.handlerResizeWindow = function () {
FORM.forEach(form => {
if (form) {
this.setPlaceholder(form);
// this.setSettingsSearchInHeader(form);
}
});
}
// задаем настройки поиску находящийся в шапке
// this.setSettingsSearchInHeader = function (form) {
// if (this.getParameter('headerType') && !this.getParameter('headerBreakpoint')) {
// this.setTypeSearch(form);
// this.setSlideDirection(form);
// } else {
// let widthWindow = document.body.getBoundingClientRect().width;
// this.removeClassTypeSearch(form);
// this.removeClassSlideDirection(form);
// this.getParameter('headerBreakpoint').map(item => {
// let min = typeof item.breakpoint[0] === 'number' ? item.breakpoint[0] : rangeDevices[item.breakpoint[0]].value;
// let max = typeof item.breakpoint[1] === 'number' ? item.breakpoint[1] : rangeDevices[item.breakpoint[1]].value;
// if (min === 0 && widthWindow <= max) {
// this.setTypeSearch(form, item);
// item.type === 'short' && this.setSlideDirection(form, item);
// } else if (max === 0 && widthWindow > min) {
// this.setTypeSearch(form, item);
// item.type === 'short' && this.setSlideDirection(form, item);
// } else if (widthWindow > min && widthWindow <= max) {
// this.setTypeSearch(form, item);
// item.type === 'short' && this.setSlideDirection(form, item);
// }
// })
// }
// }
// устанавливаем тип поиска
// this.setTypeSearch = function (form, item) {
// if (this.getParameter('headerType') && !this.getParameter('headerBreakpoint')) {
// form.classList.add(`form-search_type_${this.getParameter('headerType')}`)
// } else {
// form.classList.add(`form-search_type_${item.type}`)
// }
// }
// устанавливаем направление поиска если он "short"
// this.setSlideDirection = function (form, item) {
// if (this.getParameter('headerType') && !this.getParameter('headerBreakpoint')) {
// this.getParameter('headerType') === 'short' ? form.classList.add(`form-search_slide-direction_${this.getParameter('headerSlideDirection')}`) : null;
// } else {
// form.classList.add(`form-search_slide-direction_${item.slideDirection}`)
// }
// }
// this.removeClassTypeSearch = function (form) {
// form.classList.remove(...[...form.classList].filter(n => n.startsWith('form-search_type_')));
// }
// this.removeClassSlideDirection = function (form) {
// form.classList.remove(...[...form.classList].filter(n => n.startsWith('form-search_slide-direction_')));
// }
// проверка на наличие кастомных настроек
// this.checkingSettings = function () {
// // return typeof customSettings !== 'undefined' || (typeof customSettings === 'object' && Object.keys(customSettings).length > 0);
// return (typeof customSettings === 'object' && Object.keys(customSettings).length > 0);
// }
// проверка на наличе параметра в кастомных настройках
// this.checkingParameter = function (value) {
// return typeof customSettings[value] !== 'undefined'
// }
// // получаем параметр из кастомных настроек, если там нету, то из значений по умолчанию
// this.getParameter = function (value) {
// // console.log(value, this.checkingSettings() && this.checkingParameter(value) ? customSettings[value] : DEFAULT_SETTINGS[value])
// return this.checkingSettings() && this.checkingParameter(value) ? customSettings[value] : DEFAULT_SETTINGS[value];
// }
// задаем плейсхолдер
this.setPlaceholder = function (search) {
switch (typeof settings.placeholder) {
case 'string':
search.querySelector('.form__input').setAttribute('placeholder', settings.placeholder);
break;
case 'object':
let checkRange = Object.entries(settings.placeholder).find(item => document.body.classList.contains(`js-device-${item[0]}`));
search.querySelector('.form__input').setAttribute('placeholder', checkRange ? checkRange[1] : 'Поиск');
break;
default:
break;
}
}
// событие при изменении поля
this.handlerChangeOnTextField = function (e, form) {
// добавляем кнопку очистить поле
if (e.currentTarget.value !== '') {
this.addButtonClear(form);
this.addClassFilled(form);
} else {
this.removeButtonClear(form);
this.removeClasses(form);
}
}
// добавляем кнопку очистить поле
this.addButtonClear = function (form) {
if (settings.clear) {
if (!form.querySelector('.form__button-clear')) {
form.querySelector('.form__field-query').insertAdjacentHTML('beforeend',
`<button class="form__button-clear">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
<path fill="gray" d="M1.793 1.796a1 1 0 000 1.414l4.793 4.793-4.793 4.793a1 1 0 001.414 1.414L8 9.417l4.793 4.793a1 1 0 001.414-1.414L9.414 8.003l4.793-4.793a1 1 0 00-1.414-1.414L8 6.589 3.207 1.796a1 1 0 00-1.414 0z" />
</svg>
</button>`);
form.classList.add('is-button-clear');
form.querySelector('.form__button-clear').addEventListener('click', e => this.handlerClickOnButtonClear(e, form));
}
}
}
// удаляем кнопку очистить поле
this.removeButtonClear = function (search) {
if (search.querySelector('.form__button-clear')) {
search.querySelector('.form__button-clear').remove();
search.classList.remove('is-button-clear');
}
}
// событие клика по кнопке очистить поле
this.handlerClickOnButtonClear = function (e, form) {
e.preventDefault();
form.querySelector('.form__input').value = '';
this.removeClasses(form);
this.removeResult(form);
this.removeButtonClear(form);
}
// удаление классов
this.removeClasses = function (search) {
search.classList.remove('is-results');
search.classList.remove('is-focus');
search.classList.remove('is-open');
search.classList.remove('is-filled');
}
// добавляем класс что поле заполнено
this.addClassFilled = function (form) {
form.classList.add('is-filled');
}
// удаляем результаты поиска
this.removeResult = function (search) {
search.querySelector('.search-result') ? search.querySelector('.search-result').remove() : null;
}
if (FORM) {
this.init();
}
}
<div class="search">
<form class="form form-full form-search search__form">
<div class="form__field form__field-query search__item">
<input class="form__input" type="text" placeholder="">
</div>
<div class="form__action search__actions">
<button class="form__submit search__submit button button-primary button_size_norma">Поиск</button>
</div>
</form>
</div>
new Search({
clear: true, // true or false
placeholder: {
desktop: 'Введите артикул или наименование',
mobile: 'Поиск',
},
inHeader: {
type: 'short', // 'short' or 'full'
direction: 'left', // 'left' or 'right
}
});
window.Search = function(settings) {
const FORM = document.querySelectorAll('.form-search');
const SETTINGS = {
clear: true,
placeholder: {
desktop: 'Введите артикул или наименование',
mobile: 'Поиск',
},
inHeader: {
type: 'full',
direction: 'right',
}
}
// начало
this.init = function () {
if (FORM.length) {
FORM.forEach(form => {
if (form) {
// если поиск находится в шапке сайта
// if ((typeof settings.inHeader === 'undefined' && SETTINGS.inHeader) || settings.inHeader) {
// if (form.closest('.header-desktop, .header-tablet')) {
// if ((settings.inHeader && settings.inHeader.type) || SETTINGS.inHeader.type) {
// form.classList.add(`search_type_${(settings.inHeader && settings.inHeader.type) || SETTINGS.inHeader.type}`);
// }
// if ((settings.inHeader && settings.inHeader.direction) || SETTINGS.inHeader.direction) {
// form.classList.add(`search_direction_${(settings.inHeader && settings.inHeader.direction) || SETTINGS.inHeader.direction}`);
// }
// }
// }
if ((typeof settings.clear === 'undefined' && SETTINGS.clear) || settings.clear) {
this.clickOnChangeText(form);
if (form.querySelector('.form__input').value !== '') {
this.addButtonClear(form);
}
}
this.setPlaceholder(form);
}
});
window.addEventListener('resize', e => {
this.handlerResizeWindow();
}, true);
}
}
// событие на изменение разрешения браузера
this.handlerResizeWindow = function () {
FORM.forEach(search => {
if (search.querySelector('form')) {
this.setPlaceholder(search);
}
});
}
// задаем плейсхолдер
this.setPlaceholder = function (search) {
let text = search.querySelector('.form__input');
if (document.body.getBoundingClientRect().width <= 767) {
if (text.getAttribute('placeholder') !== ((settings.placeholder && settings.placeholder.mobile) || SETTINGS.placeholder.mobile)) {
text.setAttribute('placeholder', (settings.placeholder && settings.placeholder.mobile) || SETTINGS.placeholder.mobile);
}
} else {
if (text.getAttribute('placeholder') !== ((settings.placeholder && settings.placeholder.desktop) || SETTINGS.placeholder.desktop)) {
text.setAttribute('placeholder', (settings.placeholder && settings.placeholder.desktop) || SETTINGS.placeholder.desktop);
}
}
}
// событие при изменении поля
this.clickOnChangeText = function (form) {
form.querySelector('.form__input').addEventListener('input', e => {
if (e.currentTarget.value !== '') {
this.addButtonClear(form);
} else {
this.removeButtonClear(form);
}
});
}
// добавляем кнопку очистить поле
this.addButtonClear = function (form) {
if (!form.querySelector('.form__button-clear')) {
form.querySelector('.form__field-query').insertAdjacentHTML('beforeend', '<button class="form__button-clear">Очистить</button>');
form.classList.add('is-button-clear');
this.clickOnButtonClear(form);
}
}
// удаляем кнопку очистить поле
this.removeButtonClear = function (search) {
search.querySelector('.form__button-clear').remove();
search.classList.remove('is-button-clear');
}
// событие клика по кнопке очистить поле
this.clickOnButtonClear = function (search) {
search.querySelector('.form__button-clear').addEventListener('click', e => {
e.preventDefault();
search.querySelector('.form__input').value = '';
this.removeClasses(search);
this.removeResult(search);
this.removeButtonClear(search);
});
}
// удаление классов
this.removeClasses = function (search) {
search.classList.remove('is-results');
search.classList.remove('is-focus');
search.classList.remove('is-open');
}
// удаляем результаты поиска
this.removeResult = function (search) {
search.querySelector('.search-result') ? search.querySelector('.search-result').remove() : null;
}
if (FORM) {
this.init();
}
}