DOMContentLoaded в шаблонах компонентов

При разработке шаблонов компонентов часто встречается такой код:


document.addEventListener("DOMContentLoaded", function () {
    // Инициализация скриптов компонента
});

В контексте решений, где компоненты могут подгружаться в модальные окна или через AJAX, такой подход приводит к проблемам.

В чём проблема

Событие DOMContentLoaded срабатывает один раз — когда основной HTML-документ загружен и разобран браузером.

Если ваш компонент:

  • открывается в модальном окне и HTML подгружается динамически;
  • подставляется на страницу через AJAX;
  • перерисовывается без полной перезагрузки страницы,

то на момент, когда скрипт внутри шаблона компонента подключается, событие DOMContentLoaded уже давно прошло.

В результате:

  • обработчик добавляется после срабатывания события;
  • функция инициализации никогда не выполнится.

К каким сложностей это приводит

В таких сценариях перестают работать:

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

При этом на "обычной" странице без AJAX всё может работать корректно, из-за чего ошибка долго остаётся незамеченной.

Как делать правильно

  1. Не привязывать код к DOMContentLoaded внутри шаблона компонента

    В большинстве случаев HTML компонента уже есть в DOM к моменту выполнения скрипта. Можно вызывать инициализацию сразу:

    
    (function () {
        // Инициализация скриптов компонента
    })();
    
  2. Использовать отдельную функцию и вызывать её после вставки компонента
  3. Вынесите инициализацию в функцию:

    
    function initMyComponent(container) {
        // container — корневой элемент компонента
        // навешиваем обработчики, запускаем плагины и т.д.
    }
    

    А затем вызывайте её:

    • после AJAX-подгрузки HTML;
    • после открытия модального окна, когда разметка вставлена в DOM.
  4. Использовать делегирование событий
  5. Вместо того чтобы навешивать обработчики на элементы при загрузке, используйте делегирование:

    
    document.addEventListener("click", function (e) {
        if (e.target.closest(".js-my-button")) {
            // Обработка клика по кнопке компонента
        }
    });
    

    Тогда новые элементы, добавленные через AJAX или в модалку, будут работать без повторной инициализации.

Заключение

В шаблонах компонентов не стоит использовать document.addEventListener("DOMContentLoaded", ...), потому что событие уже могло отработать до подключения вашего кода. Для компонентов, которые могут загружаться динамически, лучше вызывать инициализацию сразу, использовать отдельные init-функции и/или делегирование событий.