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

Основы работы с кастомными событиями
В 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);
Производительность
- Избегайте частых событий (например, при скролле)
- Отписывайтесь от событий при уничтожении компонентов
- Используйте объектные события для изолированных компонентов
Совместимость
API кастомных событий доступно во всех современных версиях 1С-Битрикс (ядро D7, версия 20.0.0+).
Типичные ошибки
- Утечки памяти
Не забывайте отписываться от событий при удалении компонентов:// При разрушении компонента BX.removeCustomEvent(this, 'EventName', handler);
- Неоднозначные имена
Избегайте общих имен вродеupdate
илиchange
. Используйте префиксы. - Смешивание с DOM-событиями
Кастомные события Bitrix предназначены для логики приложения, DOM-события - для взаимодействия с интерфейсом. - Ожидание возвращаемых значений
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С-Битрикс — мощный инструмент для создания:
- Слабосвязанных компонентов
- Масштабируемых фронтенд-архитектур
- Легко поддерживаемых систем
- Тестируемых модулей
Используйте приведенные примеры как основу для ваших решений. Начните с простых сценариев и постепенно внедряйте событийную модель в сложные проекты.