Повесить и снять обработчик событий, функции 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
, так и специальные события Bitrixhandler
функция обработчик
Создатели платформы рекомендуют оборачивать обработчик в 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>
Кастомные события
В Битрикс кастомные или пользовательские события реализованы за счет двух методов:
BX.onCustomEvent()
функция вызывает обработчики события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)
})