При работе с 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:
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.В интерфейсах с 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();
});
Для сложных интерфейсов важно, чтобы шаги не зависели от
порядка загрузки данных. 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' }
}
]);
Такой подход гарантирует, что каждый шаг отображается только после полной загрузки необходимых элементов.
document.querySelector перед запуском шага.driver.reset()),
чтобы избежать конфликтов.Эти методы обеспечивают гибкую и устойчивую интеграцию Driver.js с любыми AJAX-интерфейсами, позволяя создавать пошаговые гиды даже для полностью динамических страниц.