В статье разбираем, зачем и как правильно «отвязывать» события, работая с ядром JavaScript-библиотеки 1С-Битрикс, — от простых кликов до тонких сценариев с динамическим DOM.

1. Зачем вообще снимать обработчики
- Освобождение памяти. Навешанные, но больше не нужные слушатели мешают сборщику мусора и со временем замедляют интерфейс.
- Предотвращение дублирования логики. При частичном перерендере компонентов можно случайно «накидать» несколько одинаковых слушателей на один узел.
- Безопасное «раскрепощение» элементов перед удалением из DOM. Если не снять обработчики, в старых браузерах возможно утекание памяти.
2. Синтаксис BX.unbind
BX.unbind(
DOMNode node, // целевой элемент
string eventName,// тип события, например 'click'
Function callback // та же функция-обработчик, что и при bind
);
Функция удаляет конкретный обработчик callback
события eventName
у узла node
.
3. База: минимальный пример
<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.bind
, снять нельзя — она больше нигде не доступна.
4. Удаляем после первого выполнения
Нужна логика «сработал один раз — больше не слушаем»? Простейший паттерн:
function once(cb) {
return function wrapOnce(e) {
BX.unbind(this, e.type, wrapOnce);
return cb.apply(this, arguments);
}
}
// подключаем
BX.bind(node, 'click', once(function () {
console.log('Это сообщение вы увидите только один раз');
}));
5. Пример в модальном окне (BX.PopupWindow
)
const popup = new BX.PopupWindow('demo-popup', null, {
content: 'Нажмите Esc, чтобы закрыть',
closeByEsc: true,
autoHide: true,
events: {
onPopupShow: function () {
BX.bind(document, 'keydown', onEscape);
},
onPopupClose: function () {
BX.unbind(document, 'keydown', onEscape); // важно во избежание утечек
}
}
});
function onEscape(e) {
if (e.key === 'Escape') {
popup.close();
}
}
popup.show();
6. Отвязка делегированного обработчика
Когда вместо BX.bind
используется делегирование (BX.bindDelegate
), схема такая же — передаём тот же колбэк:
const list = BX('todo-list');
function onItemClick(e) {
if (BX.test(BX.getEventTarget(e), {tag: 'LI'})) {
BX.toggleClass(BX.getEventTarget(e), 'done');
}
}
BX.bindDelegate(list, 'click', {tag: 'LI'}, onItemClick);
// …позже:
BX.unbind(list, 'click', onItemClick);
7. Работаем с контекстом через BX.delegate
Если нужно сохранить контекст объекта, используйте BX.delegate
, но тоже храните ссылку:
class Counter {
constructor(node) {
this.node = node;
this.value = 0;
this.clickH = BX.delegate(this.onClick, this);
BX.bind(this.node, 'click', this.clickH);
}
onClick() {
this.value++;
this.node.textContent = this.value;
if (this.value >= 5) {
BX.unbind(this.node, 'click', this.clickH);
}
}
}
new Counter(BX('counter-btn'));
8. Снятие всех обработчиков разом
Для крайних случаев библиотека предлагает BX.unbindAll
. Она устраняет все слушатели с указанного узла или, если аргумент не передан, с всего документа.
BX.unbindAll(node); // осторожно: после этого у node не останется ни одного обработчика
9. Частые ошибки и как их исправить
Ошибка | Как проявляется | Решение |
---|---|---|
Передаёте новую (анонимную) функцию при unbind |
Обработчик остаётся | Храните ссылку в переменной |
Используете стрелку вместо обычной функции, а контекст важен | this становится window |
Либо не используйте стрелку, либо обвяжите через BX.delegate |
Создаёте несколько обработчиков в цикле и снимаете один | «Прыгающее» поведение | Храните массив обработчиков, снимайте все |
10. Когда лучше не использовать BX.unbind
- Одноразовые события — проще навесить через
once()
(см. выше). - Современные проекты, где уже есть фреймворк (Vue/React). Там жизненным циклом компонентов управляет сам фреймворк; вручную снимать события не нужно.
- Глобальные события (scroll, resize). Чаще используют «пассивное» слушание + debounce/throttle.
11. Итог
BX.unbind
— маленькая, но важная функция ядра Bitrix:
- снимает конкретный обработчик, не трогая остальные;
- работает одинаково во всех браузерах, скрывая под капотом тонкости
removeEventListener
; - помогает держать интерфейс «чистым» и быстрым.
Соблюдайте правило «навесил — снимай» — и ваши виджеты в Битриксе будут работать стабильно даже после тысяч кликов и динамических перерисовок.