Интеграция с AJAX

При работе с AJAX-запросами возникает задача управления элементами, которые добавляются на страницу динамически. Driver.js по умолчанию инициализирует шаги на момент вызова .start(), поэтому элементы, загруженные после этого, не будут отображены. Для корректной работы с динамическим контентом нужно учитывать отсроченную инициализацию шагов и использование обработчиков событий.

Отложенная инициализация шагов

Driver.js принимает массив шагов в формате:

const driver = new Driver();

driver.defineSteps([
  {
    element: '#menu',
    popover: {
      title: 'Главное меню',
      description: 'Здесь находятся все разделы приложения',
      position: 'bottom'
    }
  }
]);

Если элемент #menu появляется на странице только после AJAX-загрузки, необходимо отложить определение шагов до момента появления элемента:

fetch('/api/getMenu')
  .then(response => response.text())
  .then(html => {
    document.querySelector('#menuContainer').innerHTML = html;

    const driver = new Driver();
    driver.defineSteps([
      {
        element: '#menu',
        popover: {
          title: 'Меню загружено',
          description: 'Теперь меню доступно после AJAX',
          position: 'bottom'
        }
      }
    ]);
    driver.start();
  });

Использование MutationObserver для динамических элементов

Для сценариев, где элементы могут появляться несколько раз или непредсказуемо, удобнее использовать MutationObserver:

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    mutation.addedNodes.forEach((node) => {
      if (node.matches && node.matches('#dynamicButton')) {
        const driver = new Driver();
        driver.defineSteps([
          {
            element: '#dynamicButton',
            popover: {
              title: 'Динамическая кнопка',
              description: 'Эта кнопка загружена через AJAX',
              position: 'top'
            }
          }
        ]);
        driver.start();
        observer.disconnect(); // отключение после первого срабатывания
      }
    });
  });
});

observer.observe(document.body, { childList: true, subtree: true });

Ключевые моменты:

  • MutationObserver отслеживает добавление элементов в DOM.
  • После появления элемента можно безопасно инициализировать шаги Driver.js.
  • Необходимо отключать наблюдателя, если больше нет необходимости отслеживать изменения.

Интеграция с динамическими таблицами и списками

В интерфейсах с AJAX-таблицами (DataTables, AG Grid, кастомные списки) важно, чтобы **элементы, на которые указывают шаги, существовали в DOM в момент вызоваdriver.start()`**. Часто используется комбинация событий рендера и отложенного старта:

function initDriverAfterTableRender() {
  if (document.querySelectorAll('.table-row').length > 0) {
    const driver = new Driver();
    driver.defineSteps([
      {
        element: '.table-row:first-child',
        popover: {
          title: 'Первая строка таблицы',
          description: 'Информация загружена динамически',
          position: 'right'
        }
      }
    ]);
    driver.start();
  } else {
    setTimeout(initDriverAfterTableRender, 100); // повторная проверка
  }
}

fetch('/api/getTableData')
  .then(response => response.json())
  .then(data => {
    renderTable(data);
    initDriverAfterTableRender();
  });

Управление последовательностью шагов при AJAX

Для сложных интерфейсов важно, чтобы шаги не зависели от порядка загрузки данных. Driver.js позволяет использовать коллбэки onNext и onPrevious:

driver.defineSteps([
  {
    element: '#step1',
    popover: { title: 'Шаг 1', description: 'Загружено через AJAX', position: 'bottom' },
    onNext: () => fetch('/api/step2')
                    .then(res => res.text())
                    .then(html => {
                      document.querySelector('#step2Container').innerHTML = html;
                    })
  },
  {
    element: '#step2',
    popover: { title: 'Шаг 2', description: 'Теперь элемент доступен', position: 'right' }
  }
]);

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

Советы по стабильности и производительности

  1. Проверка наличия элемента: использовать document.querySelector перед запуском шага.
  2. Отложенный старт: при большом количестве шагов с AJAX лучше запускать Driver.js после полной загрузки всех данных.
  3. Очистка DOM: перед повторной инициализацией шагов удалять предыдущие экземпляры Driver.js (driver.reset()), чтобы избежать конфликтов.
  4. Минимизация MutationObserver: ограничивать область наблюдения и отключать его после выполнения задачи для снижения нагрузки на браузер.

Эти методы обеспечивают гибкую и устойчивую интеграцию Driver.js с любыми AJAX-интерфейсами, позволяя создавать пошаговые гиды даже для полностью динамических страниц.