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

Кастомные события в 1С-Битрикс: руководство по BX.onCustomEvent

Кастомные события — мощный инструмент для создания слабосвязанных, поддерживаемых фронтенд-архитектур в 1С-Битрикс. С помощью BX.addCustomEvent и BX.onCustomEvent вы можете создавать сложные взаимодействия между компонентами, синхронизировать виджеты и строить событийные шины без лишних зависимостей.

В этой статье — практическое руководство с 12 рабочими примерами, готовыми к использованию в ваших проектах.

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

Основы работы с кастомными событиями

В 1С-Битрикс доступны два типа кастомных событий:

1. Глобальные события (без привязки к объекту):

// Подписка
BX.addCustomEvent('App:Ready', function(staticParams, payload) {
  // Логика обработки
});
// Инициирование события
BX.onCustomEvent('App:Ready', { data: "приложение запущено" });

2. События на конкретном объекте:

const widget = { id: 'weather-widget' };
// Подписка
BX.addCustomEvent(widget, 'Data:Updated', function(staticParams, payload) {
  console.log('Данные обновлены:', payload);
});
// Инициирование
BX.onCustomEvent(widget, 'Data:Updated', { temperature: 24 });

Каждый обработчик получает два параметра:

  • staticParams — данные, переданные при подписке (не изменяются)
  • payload — динамические данные, передаваемые при инициации события

Практические примеры

1. Шина приложения

(function() {
  // Подписка на событие инициализации
  BX.addCustomEvent('App:Ready', function(cfg, data) {
    console.log(`[${cfg.name}] Статус:`, data.status);
    if (data.callback) data.callback();
  }, {name: 'MainModule'});
  // Инициирование события
  setTimeout(() => {
    BX.onCustomEvent('App:Ready', {
      status: 'loaded',
      callback: () => console.log('UI компоненты инициализированы')
    });
  }, 1000);
})();

2. Взаимодействие виджетов

(function() {
  // Виджет корзины
  const cart = {
    id: 'cart-001',
    items: [],
    addItem: function(product) {
      this.items.push(product);
      // Генерируем событие
      BX.onCustomEvent(this, 'Cart:ItemAdded', {
        product: product,
        count: this.items.length
      });
    }
  };
  // Подписчик 1: Обновление счетчика
  BX.addCustomEvent(cart, 'Cart:ItemAdded', function(_, payload) {
    const counter = document.getElementById('cart-counter');
    if (counter) counter.textContent = payload.count;
  });
  // Подписчик 2: Логирование
  BX.addCustomEvent(cart, 'Cart:ItemAdded', function(_, payload) {
    console.log(`Товар добавлен: ${payload.product.name}`);
  });
  // Пример использования
  cart.addItem({id: 101, name: 'Ноутбук', price: 89990});
})();

3. Одноразовые обработчики

(function() {
  function once(eventName, handler) {
    const wrapper = function(staticParams, payload) {
      // Отписываемся перед выполнением
      BX.removeCustomEvent(eventName, wrapper);
      handler.call(this, staticParams, payload);
    };
    BX.addCustomEvent(eventName, wrapper);
  }
  // Пример использования
  once('User:FirstLogin', function(_, data) {
    console.log('Первая авторизация пользователя:', data.userId);
  });
  // Эмулируем событие
  BX.onCustomEvent('User:FirstLogin', {userId: 42});
})();

4. Отписка от событий

(function() {
  function onScroll(_, payload) {
    console.log('Позиция скролла:', payload.position);
  }
  // Подписываемся
  BX.addCustomEvent('Window:Scroll', onScroll);
  // Позже отписываемся
  document.getElementById('unsubscribe-btn').addEventListener('click', () => {
    BX.removeCustomEvent('Window:Scroll', onScroll);
    console.log('Отписались от событий скролла');
  });
})();

5. Передача статических параметров

(function() {
  const loggerConfig = {
    level: 'debug',
    prefix: '[Search]'
  };
  BX.addCustomEvent('Search:Complete', function(cfg, data) {
    if (cfg.level === 'debug') {
      console.log(`${cfg.prefix} Поиск "${data.query}": ${data.results} результатов`);
    }
  }, loggerConfig);
  // Генерируем событие
  BX.onCustomEvent('Search:Complete', {
    query: 'смартфон',
    results: 124
  });
})();

6. Интеграция с DOM-событиями

(function() {
  document.querySelectorAll('.buy-btn').forEach(button => {
    button.addEventListener('click', function() {
      const productId = this.dataset.id;
      BX.onCustomEvent('Catalog:ProductClick', {
        id: productId,
        element: this
      });
    });
  });
  // Обработчик кастомного события
  BX.addCustomEvent('Catalog:ProductClick', function(_, payload) {
    console.log('Выбран товар:', payload.id);
    // Дополнительная логика обработки...
  });
})();

7. Асинхронные операции с колбэками

(function() {
  // Обработчик данных
  BX.addCustomEvent('Data:LoadRequest', function(_, payload) {
    if (!payload || typeof payload.complete !== 'function') return;

    // Эмуляция асинхронной загрузки
    setTimeout(() => {
      payload.complete({items: [1, 2, 3], total: 3});
    }, 500);
  });
  // Функция для загрузки данных
  function loadData() {
    return new Promise(resolve => {
      BX.onCustomEvent('Data:LoadRequest', {
        complete: resolve
      });
    });
  }
  // Использование
  loadData().then(data => {
    console.log('Данные загружены:', data);
  });
})();

8. Паттерн "Отмена действия"

(function() {
  // Подписчик может отменить действие
  BX.addCustomEvent('Form:BeforeSubmit', function(_, ctx) {
    if (!ctx.form.checkValidity()) {
      ctx.cancel = true;
      ctx.message = 'Форма заполнена неверно';
    }
  });
  function submitForm(form) {
    const context = {
      form: form,
      cancel: false,
      message: ''
    };

    BX.onCustomEvent('Form:BeforeSubmit', context);

    if (context.cancel) {
      alert(context.message);
      return false;
    }

    form.submit();
    return true;
  }
  // Пример использования
  const form = document.getElementById('order-form');
  form.addEventListener('submit', function(e) {
    e.preventDefault();
    submitForm(this);
  });
})();

9. Работа с контекстом

(function() {
  const imageGallery = {
    name: 'ProductGallery',
    log: function(message) {
      console.log(`[${this.name}] ${message}`);
    }
  };
  function onImageLoad(_, payload) {
    this.log(`Изображение загружено: ${payload.url}`);
  }
  // Привязываем контекст
  const boundHandler = onImageLoad.bind(imageGallery);

  BX.addCustomEvent('Gallery:ImageLoaded', boundHandler);
  // Инициируем событие
  BX.onCustomEvent('Gallery:ImageLoaded', {
    url: '/images/product.jpg'
  });
})();

10. Взаимодействие между модулями

(function() {
  // Модуль геолокации
  const geoService = {
    currentCity: null,
    setCity: function(city) {
      this.currentCity = city;
      BX.onCustomEvent('Geo:CityChanged', {city: city});
    }
  };
  // Модуль доставки
  BX.addCustomEvent('Geo:CityChanged', function(_, payload) {
    console.log(`Город изменен на ${payload.city} - обновляем пункты выдачи`);
    // Логика обновления данных о доставке...
  });
  // Модуль ценообразования
  BX.addCustomEvent('Geo:CityChanged', function(_, payload) {
    console.log(`Проверяем региональные цены для ${payload.city}`);
    // Логика обновления цен...
  });
  // Пример использования
  geoService.setCity('Москва');
})();

11. Инкапсулированная шина событий

(function(global) {
  const eventBus = {};
  const channel = { ns: 'AppEvents' };

  // Публичный API
  eventBus.on = function(event, handler) {
    BX.addCustomEvent(channel, `App:${event}`, handler);
  };

  eventBus.off = function(event, handler) {
    BX.removeCustomEvent(channel, `App:${event}`, handler);
  };

  eventBus.emit = function(event, data) {
    BX.onCustomEvent(channel, `App:${event}`, data);
  };

  global.AppEventBus = eventBus;
})(window);
// Использование
AppEventBus.on('Notification', function(_, message) {
  console.log('Новое уведомление:', message);
});
AppEventBus.emit('Notification', 'Заказ успешно оформлен!');

12. Интеграция с системными событиями

(function() {
  // Подписка на системное событие AJAX
  BX.addCustomEvent('onAjaxSuccess', function(_, data) {
    console.log('AJAX запрос успешен:', data);
    BX.onCustomEvent('App:AJAXComplete', {status: 'success', data: data});
  });

  // Кастомная обработка
  BX.addCustomEvent('App:AJAXComplete', function(_, payload) {
    if (payload.status === 'success') {
      // Обновление интерфейса
    }
  });
})();

Советы по использованию

Соглашение об именовании

Используйте структурированные имена событий:

[Компонент]:[Действие]

Примеры:

  • User:LoginSuccess
  • Catalog:FilterChanged
  • Cart:ItemRemoved

Отладка событий

Для просмотра активных подписок используйте в консоли:

console.dir(BX._customEvents);

Производительность

  1. Избегайте частых событий (например, при скролле)
  2. Отписывайтесь от событий при уничтожении компонентов
  3. Используйте объектные события для изолированных компонентов

Совместимость

API кастомных событий доступно во всех современных версиях 1С-Битрикс (ядро D7, версия 20.0.0+).


Типичные ошибки

  1. Утечки памяти
    Не забывайте отписываться от событий при удалении компонентов:
    // При разрушении компонента
    BX.removeCustomEvent(this, 'EventName', handler);
  2. Неоднозначные имена
    Избегайте общих имен вроде update или change. Используйте префиксы.
  3. Смешивание с DOM-событиями
    Кастомные события Bitrix предназначены для логики приложения, DOM-события - для взаимодействия с интерфейсом.
  4. Ожидание возвращаемых значений
    BX.onCustomEvent не возвращает результатов. Для получения данных используйте колбэки в payload.

Шпаргалка по API

// Глобальные события
BX.addCustomEvent(eventName, handler[, staticParams]);
BX.removeCustomEvent(eventName, handler);
BX.onCustomEvent(eventName[, payload]);
// События на объекте
BX.addCustomEvent(targetObject, eventName, handler[, staticParams]);
BX.removeCustomEvent(targetObject, eventName, handler);
BX.onCustomEvent(targetObject, eventName[, payload]);

Заключение

Кастомные события в 1С-Битрикс — мощный инструмент для создания:

  • Слабосвязанных компонентов
  • Масштабируемых фронтенд-архитектур
  • Легко поддерживаемых систем
  • Тестируемых модулей

Используйте приведенные примеры как основу для ваших решений. Начните с простых сценариев и постепенно внедряйте событийную модель в сложные проекты.

Теги:  кастомные события, BX.onCustomEvent, BX.addCustomEvent, фронтенд-архитектура, события в 1С-Битрикс, примеры событий


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

Модули и компоненты для «1С-Битрикс»

оценка производится на основе предоставленного Технического Задания

от 20 000 рублей
Разработка дополнительных модулей для 1С-Битрикс, расширение функционала, внедрение любых решений, требующихся для выполнения ваших бизнес-задач.

* стоимость зависит от конкретной задачи, ее объема и сложности выполняемых работ.

Лендинг

от 3 дней

от 25 000 рублей

Разработка одностраничного сайта на платформе Битрикс

* стоимость зависит от наличия верстки, использования готового решения и т.д.

Участие в проекте

привлечение в проект на part-time основе

от 20 000 рублей / неделя

Возможно участие в проекте на ежедневной основе, как разработчика. Занятость - до 20 часов в неделю
Минимальный срок - одна неделя.

* сумма фиксированная