Yandex Metrika
sanches.free

Чистый 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 дней гарантии