Полный цикл в digital

Повесить и снять обработчик событий, функции bindDelegate () и unbind ()

В стандартном JavaScript вы, вероятно, привыкли к addEventListener.

В Битрикс, та же задача решается «платформенным» способом — через BX.bind. Это даёт единый API, совместимый со старыми браузерами, интегрированный с остальными утилитами ядра Bitrix и удобный для отладки. Функция подключена во всех шаблонах ядра, поэтому никакие дополнительные файлы включать не нужно.

void BX.bind(
    // элемент или его id-строка
    el,
    // имя события (click, mouseover, bxchange …)
    event,
    // callback-функция
    handler
);
  • el DOM-элемент или строка-id. Если передана строка, внутри вызывается BX(el), аналог document.getElementById
  • event строка с именем события. Принимает как нативные click, keyup, так и специальные события Bitrix
  • handler функция обработчик

Создатели платформы рекомендуют оборачивать обработчик в BX.delegate/BX.proxy. Так вы сможете легко удалить слушатель через BX.unbind и повторно использовать одну функцию для многих элементов.

Клик по кнопке

<button id="btn-alert">Нажми меня</button>
<script>
BX.bind('btn-alert', 'click', function () {
    alert('Привет из BX.bind!');
});
</script>

Использование контекста через BX.delegate

<ul id="product-list">
    <li data-id="101">Товар #101</li>
    <li data-id="102">Товар #102</li>
</ul>
<script>
var App = {
    handleProductClick: function (e) {
        // BX.proxy_context всегда указывает на реальный элемент, вызвавший событие
        var id = BX.proxy_context.getAttribute('data-id');
        console.log('Товар выбран:', id);
    }
};
BX.bind('product-list', 'click',
    BX.delegate(App.handleProductClick, App)
);
</script>

BX.proxy_context экономит время, не нужно вычислять e.target.

Делегирование через BX.bindDelegate

Если список элементов динамический (добавляется позже), вместо того, чтобы перевешивать события, привяжитесь к «контейнеру» раз и навсегда:

<table id="orders">
    <tr data-order="501"><td>501</td><td><a class="delete" href="#">Удалить</a></td></tr>
</table>
<script>
BX.bindDelegate(
    BX('orders'), // узел-контейнер
    'click', // событие
    {className: 'delete'}, // фильтр цели
    function () {
        var row = BX.proxy_context.closest('tr');
        console.log('Удаляем заказ', row.dataset.order);
        BX.remove(row);
    }
);
</script>

Открепление и уборка

function logResize() { console.log('resize'); }
// подвесили
BX.bind(window, 'resize', logResize);
// когда больше не нужно
BX.unbind(window, 'resize', logResize);
// или BX.unbindAll(window), уберёт все события с объекта

Отловить событие на динамически изменяющихся страницах

Один из самых эффективных способов «поймать» событие на динамически изменяющихся страницах Битрикс. Он устраняет проблему, когда элементы создаются JavaScript-ом уже после подключения обработчиков, и вам приходится заново «привязывать» события.

BX.bindDelegate(
    // родитель-контейнер
    parentNode,
    // имя DOM-события
    eventName,
    // фильтр целевых узлов
    isTarget,
    // колбэк-обработчик
    handler
);
Параметр Тип Что означает
parentNode HTMLElement Узел, на который вешается единственный реальный обработчик
eventName String Любое поддерживаемое браузером событие («click», «input», «keydown» и т.д.)
isTarget Object Фильтр: указываем свойства, которые должен иметь дочерний узел-источник
handler Function Выполняется при всплытии события, если узел прошёл фильтр

Настраиваем фильтр isTarget:

{
    // по тегу
    tagName  : 'A',
    // по классу
    className: 'btn--blue',
    // по наличию атрибутов
    attr     : {
        'data-role': 'save'
    }
}

Фильтр может содержать любое подмножество полей:

  • tagName сравнивается без учёта регистра
  • className / class должен содержать указанный класс
  • attr объект вида { 'data-id': '15' }, значения сравниваются как строки
  • id строгое совпадение

Можно передать и функцию:

isTarget: function(node) {
    return node.dataset && node.dataset.track === 'subscribe';
}

Подсветка активного пункта меню без перезагрузки

<ul id="nav" class="nav">
    <li><a href="#">Главная</a></li>
    <li><a href="#">Услуги</a></li>
    <li><a href="#">Контакты</a></li>
</ul>
<style>
.nav a {
    padding: 6px 10px;
    display: inline-block;
}
.nav .on {
    background:#0066cc;
    color:#fff;
    border-radius:4px;
}
</style>
<script>
BX.bindDelegate(
    BX('nav'),
    'click',
    { tagName: 'A' },
    function(event) {
        event.preventDefault();
        // Снимаем старый класс
        BX.findChildren(BX('nav'), { className: 'on' }, true)
          .forEach(node => BX.removeClass(node, 'on'));
        // Ставим новый
        BX.addClass(this, 'on');
    }
);
</script>

Снять обработчик события

Зачем вообще снимать обработчики:

  • Освобождение памяти навешанные, но больше не нужные слушатели мешают сборщику мусора и со временем замедляют интерфейс.
  • Предотвращение дублирования логики при частичном перерендере компонентов можно случайно «накидать» несколько одинаковых слушателей на один узел
BX.unbind(
    // целевой элемент
    DOMNode node,
    // тип события, например 'click'
    string  eventName,
    // та же функция-обработчик, что и при bind
    Function callback
);

Базовый пример

<button id="btn">Кликни меня</button>
<script>
BX.ready(function () {
    const btn = BX('btn');
    const handler = function () {
        alert('Обработчик ещё на месте!');
    };
    BX.bind(btn, 'click', handler);
    // через 5 секунд снимаем обработчик
    setTimeout(function () {
        BX.unbind(btn, 'click', handler);
        BX.adjust(btn, {text: 'Кликни — уже тишина'});
    }, 5000);
});
</script>

Кастомные события

В Битрикс кастомные или пользовательские события реализованы за счет двух методов:

  1. BX.onCustomEvent() функция вызывает обработчики события
  2. BX.addCustomEvent() Функция назначает обработчик события, например в виде функции колбэка
BX.onCustomEvent(
    // не обязательный параметр
    Object eventObject,
    string eventName,
    Array [arEventParams]
);

Функция вызывает все обработчики события eventName для объекта eventObject (не обязательный параметр), а также все глобальные обработчики, назначенные без указания объекта. Если не указан объект, в котором возникает событие, то будут вызваны только глобальные обработчики. Обработчик будет выполнен в контексте объекта, в котором возникло событие. Значения из массива arEventParams будут переданы в качестве входных параметров обработчика.

BX.addCustomEvent(
    // не обязательный параметр
    Object eventObject,
    string eventName,
    Function eventHandler
);

Функция назначает обработчик eventHandler кастомному событию с именем eventName, возникающем в объекте eventObject (не обязательный параметр). Если eventObject не указан, то обработчик будет вызываться при каждом вызове события с таким именем в любом объекте.

Наглядный пример, как работают кастомные события:

// находим кнопку с ID button и вешаем событие клик
BX('button').addEventListener('click', function (event) {
    // функция вызывает обработчики событий hmarketingTest и передает в обработчики текст кнопки и event
    BX.onCustomEvent('hmarketingTest', [this.innerText, event]);
});
// функция назначает обработчик для события hmarketingTest в виде колбек функции
BX.addCustomEvent('hmarketingTest', function (id, event) {
    console.log(id)
    console.log(event)
})
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!