Блог разработчика 1С-Битрикс

Обработка событий в 1С-Битрикс: снимаем обработчики с помощью BX.unbind

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

Обработка событий. BX.unbind

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

  1. Одноразовые события — проще навесить через once() (см. выше).
  2. Современные проекты, где уже есть фреймворк (Vue/React). Там жизненным циклом компонентов управляет сам фреймворк; вручную снимать события не нужно.
  3. Глобальные события (scroll, resize). Чаще используют «пассивное» слушание + debounce/throttle.

11. Итог

BX.unbind — маленькая, но важная функция ядра Bitrix:

  • снимает конкретный обработчик, не трогая остальные;
  • работает одинаково во всех браузерах, скрывая под капотом тонкости removeEventListener;
  • помогает держать интерфейс «чистым» и быстрым.

Соблюдайте правило «навесил — снимай» — и ваши виджеты в Битриксе будут работать стабильно даже после тысяч кликов и динамических перерисовок.

Теги:  BX.unbind, обработка событий, JavaScript, освобождение памяти, DOM


Стоимость услуг по разработке и сопровождению сайтов на 1C-Битрикс

Лечение сайтов от вирусов

восстановление сайта и подъем версии PHP

от 25 000 рублей
Лечение сайтов на решениях АСПРО и прочих.

* полный комплекс лечения проекта и закрытия дыр

Перенос сайтов на «1С-Битрикс»

сайты на платформе «1С-Битрикс» — это удобство, надежность и высокая посещаемость

от 12 000 рублей
Перенос сайтов с любых CMS и статичных страниц на платформу «1С-Битрикс», с учетом дизайна, верстки и урл-адресов. С сохранением всей информации и структуры сайта.

* зависит от объема выполняемых работ.

Разработка интернет-магазина с готовой версткой

от 4 недель

от 90 000 рублей

* указана минимальная стоимость. Стоимость выбранной лицензии «1С-Битрикс» оплачивается отдельно.