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

2. Сигнатура и параметры
void BX.bind(
Object|DOMNode el, // элемент или его id-строка
String event, // имя события (click, mouseover, bxchange …)
Function handler // callback-функция
);
- el — сам DOM-элемент или строка-id. Если передана строка, внутри вызывается
BX(el)
— аналогdocument.getElementById
. - event — строка с именем события. Принимает как нативные (
click
,keyup
…), так и специальные события Bitrix. - handler — функция-обработчик.
Важно: создатели платформы рекомендуют оборачивать обработчик в
BX.delegate
/BX.proxy
. Так вы сможете легко удалить слушатель черезBX.unbind
и повторно использовать одну функцию для многих элементов.
3. Базовые примеры
3.1. Клик по кнопке
<button id="btn-alert">Нажми меня</button>
<script>
BX.bind('btn-alert', 'click', function () {
alert('Привет из BX.bind!');
});
</script>
3.2. Использование контекста через 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
.
4. Делегирование через 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>
Добавьте строку в таблицу хоть через AJAX — обработчик уже там.
5. Специальное событие bxchange
bxchange
— «сборное» событие, которое реагирует на change
, cut
, paste
, drop
, keyup
. Полезно для «живых» форм:
<input id="search" placeholder="Поиск…">
<script>
BX.bind('search', 'bxchange', BX.debounce(function () {
console.log('Запрос для поиска:', this.value);
}, 300));
</script>
Функция BX.debounce
(если подключён модуль main.core
) задержит вызов до тех пор, пока пользователь не перестанет вводить текст хотя бы 300 мс.
6. Открепление и уборка
function logResize() { console.log('resize'); }
// подвесили
BX.bind(window, 'resize', logResize);
// … когда больше не нужно
BX.unbind(window, 'resize', logResize);
// или BX.unbindAll(window); // уберёт все события с объекта
Используйте это при переходе между страницами SPA или разрушении Vue/React-компонентов, чтобы избежать утечек памяти.
7. Типичные ошибки и их исправления
Ошибка | Как проявляется | Как исправить |
---|---|---|
Передали строку-id, но элемента ещё нет. | Событие не срабатывает. | Поместите BX.bind внутрь BX.ready или в конец body . |
Опечатка в имени метода. | В консоли «_hadleMoreButtonClickHandler is not a function_». | Пишите правильно: _handleMoreButtonClickHandler . |
Забыли снять слушатель. | Рост потребления памяти, дублирование вызовов. | Всегда храните ссылку на обработчик и вызывайте BX.unbind . |
Использовали анонимную функцию без delegate. | Нельзя снять обработчик. | Оборачивайте через BX.delegate или выносите в именованную функцию. |
8. Крупный пример: динамическая корзина
<div id="basket">
<button class="add" data-id="201">Добавить товар 201</button>
<button class="add" data-id="202">Добавить товар 202</button>
<hr>
<ul id="basket-items"></ul>
</div>
<script>
var Basket = {
items: {},
add: function (id) {
if (!this.items[id]) {
this.items[id] = 1;
this.render();
} else {
this.items[id] += 1;
this.updateRow(id);
}
},
render: function () {
var ul = BX('basket-items');
ul.innerHTML = '';
for (var id in this.items) {
ul.innerHTML += '<li data-id="'+id+'">Товар '+id+
' <strong>'+this.items[id]+'</strong> шт. <a href="#" class="del">x</a></li>';
}
},
updateRow: function (id) {
var row = BX.findChild(BX('basket-items'), {attribute: {'data-id': id}}, true);
if (row) {
BX.findChild(row, {tag: 'strong'}, true).textContent = this.items[id];
}
},
remove: function (id) {
delete this.items[id];
this.render();
}
};
// делегируем клики по кнопкам «добавить»
BX.bindDelegate(BX('basket'), 'click', {className: 'add'},
BX.delegate(function () {
this.add(BX.proxy_context.getAttribute('data-id'));
}, Basket)
);
// делегируем клики по ссылкам «удалить»
BX.bindDelegate('basket-items', 'click', {className: 'del'},
BX.delegate(function () {
this.remove(BX.proxy_context.parentNode.getAttribute('data-id'));
}, Basket)
);
</script>
В результате:
- Нет «лейка» из обработчиков — по два делегированных слушателя на весь блок.
- Корзина обновляется мгновенно, без перезагрузки страницы.
- Код легко расширить (добавить счётчик итоговой суммы, отправку AJAX-запроса и т.д.).
9. Чек-лист перед публикацией
- Все обработчики обёрнуты в
BX.delegate
? - Сняты ли слушатели в сценариях одностраничных приложений?
- Учитываете ли вы
bxchange
для текстовых полей? - Нет ли анонимных функций, которые невозможно отвязать?
- Названия методов и переменных без опечаток?
10. Заключение
BX.bind
— инструмент фронтенд-разработчика на «1С-Битрикс». Освоив его (и парочку спутников — BX.delegate
, BX.bindDelegate
, BX.unbind
), вы избавите свои проекты от избыточного кода, улучшите производительность и сделаете логику событий предсказуемой.
Применяйте паттерны делегирования, не забывайте об уборке слушателей и пишите код, который приятно читать не только поисковым роботам, но и коллегам-разработчикам. Успехов в ваших проектах!