Чистый JavaScript в вёрстке Битрикс: DOM, события и POST без библиотек
Зачем обходиться без jQuery и BX.ready
Современные браузеры уже дают querySelector, classList и fetch/XMLHttpRequest. В шаблонах компонентов и template.php часто достаточно нескольких десятков строк, чтобы повесить обработчики на кнопки корзины, фильтры или формы — без подключения лишних библиотек и без ожидания загрузки ядра BX.
Значение «как в PHP» и одна выборка
Если переменная могла остаться неинициализированной, используют ленивое присваивание через ||. Для глобального флага удобнее явно писать в window, иначе в строгом режиме или внутри модулей поведение различается.
var userChoice = userChoice || 'по умолчанию';
window.catalogFlags = window.catalogFlags || {};Один узел по селектору:
var root = document.querySelector('[data-offer-root]');События: цикл, разовый клик, область и делегирование
Цикл по коллекции и отдельный обработчик на каждый элемент — базовый сценарий. Опция { once: true } повторяет идею «сработать один раз» без ручного removeEventListener.
Внутри конкретного блока список нужно ограничить: комбинация :scope и потомкового селектора гарантирует, что поиск не «выпрыгнет» на весь документ. Без :scope у querySelectorAll внутри элемента исторически были сюрпризы в старых движках — явный префикс остаётся хорошей привычкой.
Если разметка подгружается через AJAX, обработчик вешают на стабильный контейнер и вычисляют реальную цель через closest — так не приходится переинициализировать скрипт после каждой подмены HTML.
document.querySelectorAll('[data-buy-row]').forEach(function (btn) {
btn.addEventListener('click', function (event) {
event.preventDefault();
});
});
document.querySelectorAll('[data-buy-row]').forEach(function (btn) {
btn.addEventListener('click', function (event) {
event.preventDefault();
}, { once: true });
});
var shelf = document.querySelector('[data-shelf]');
if (shelf) {
shelf.querySelectorAll(':scope [data-buy-row]').forEach(function (btn) {
btn.addEventListener('click', function (event) {
event.preventDefault();
});
});
}
var live = document.querySelector('[data-live-list]');
if (live) {
live.addEventListener('click', function (event) {
var trigger = event.target.closest('[data-buy-row]');
if (!trigger) {
return;
}
event.preventDefault();
});
}Data-атрибуты, классы и «родители»
trigger.dataset.promoCodeчитаетdata-promo-code.node.classList.add('is-active'),classList.remove,classList.containsзаменяют ручную работу со строкойclassName.node.getAttribute('aria-expanded'),setAttribute,removeAttribute— для произвольных атрибутов.node.closest('[data-section]')поднимается к ближайшему подходящему предку (или возвращает сам узел, если он совпал).
Старт после разбора DOM и фиксация контекста
Аналог «документ готов» без jQuery:
document.addEventListener('DOMContentLoaded', function () { /* инициализация */ });
Чтобы передать нужный this в обработчик, используют Function.prototype.bind:
handler.bind(componentInstance)
Плавный переход к якорю:
document.querySelector('#reviews').scrollIntoView({ behavior: 'smooth' }); — отступ сверху обычно задают через CSS (scroll-margin-top).
AJAX: FormData и JSON-ответ
Типичный обработчик для action-параметра в духе компонентов Битрикс: собираем поля в FormData, помечаем запрос как XMLHttpRequest заголовком, ждём статус 200 и разбираем responseType='json'. URL подставляйте свой — тот же, куда целит форма компонента, или отдельный /local/ajax/....
function postJson(endpoint, payload, onSuccess, onError) {
var body = payload instanceof FormData ? payload : (function () {
var fd = new FormData();
Object.keys(payload).forEach(function (key) {
fd.append(key, payload[key]);
});
return fd;
})();
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('POST', endpoint, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status !== 200) {
onError && onError(['HTTP ' + xhr.status]);
return;
}
var data = xhr.response;
if (data && typeof data.errors !== 'undefined' && data.errors.length && onError) {
onError(data.errors);
return;
}
onSuccess && onSuccess(data);
};
xhr.send(body);
}Для простых тел удобнее URLSearchParams и заголовок application/x-www-form-urlencoded — но с FormData проще передавать файлы и повторять серверные ожидания без ручного экранирования.
На что смотреть в проде
- Передавайте
sessidтак же, как это делает стандартный фронт магазина или форм. - Проверяйте CSRF и права на стороне PHP, а не только в JS.
- Если сервер вернул HTML вместо JSON,
responseType='json'дастnull— учитывайте это вonError.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии