Driver.js — это библиотека для создания интерактивных пошаговых подсказок на веб-страницах. Для использования в SPA-приложениях сначала необходимо подключить библиотеку.
Через npm:
npm install driver.js
Импорт в модульном проекте:
import Driver from 'driver.js';
import 'driver.js/dist/driver.min.css';
Если проект не использует сборщики модулей, можно подключить через CDN:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/driver.js/dist/driver.min.css" />
<script src="https://cdn.jsdelivr.net/npm/driver.js/dist/driver.min.js"></script>
После подключения создается экземпляр Driver:
const driver = new Driver({
animate: true,
opacity: 0.75,
padding: 10,
allowClose: false,
doneBtnText: 'Готово',
closeBtnText: 'Закрыть'
});
defineSteps(steps) — задает
последовательность шагов для подсказки. Каждый шаг представляет
объект:
driver.defineSteps([
{
element: '#menu',
popover: {
title: 'Меню',
description: 'Здесь отображается навигация по приложению.',
position: 'bottom'
}
},
{
element: '#search',
popover: {
title: 'Поиск',
description: 'Поиск по всем разделам SPA.',
position: 'right'
}
}
]);
Ключевые свойства шага:
element — селектор или DOM-узел для подсветки.popover.title — заголовок всплывающей подсказки.popover.description — описание функционала.popover.position — позиция подсказки относительно
элемента (top, bottom, left,
right, center).popover.align — выравнивание внутри позиции
(start, center, end).onNext, onPrevious,
onHighlightStarted, onHighlightEnded — колбэки
для управления поведением шагов.start() — запускает последовательность
шагов. reset() — сбрасывает состояние
Driver.js. moveNext() /
movePrevious() — переход между шагами вручную.
В SPA-приложениях DOM-элементы часто рендерятся динамически, поэтому ключевым моментом является отложенное определение шагов после рендера нужного элемента.
Пример с React:
useEffect(() => {
if (document.querySelector('#profile-button')) {
driver.defineSteps([
{
element: '#profile-button',
popover: {
title: 'Профиль',
description: 'Управление вашим профилем',
position: 'left'
}
}
]);
driver.start();
}
}, [currentPage]);
Важно убедиться, что элемент существует в DOM перед созданием шага.
Если элемент появится позже, можно использовать
MutationObserver:
const observer = new MutationObserver(() => {
const el = document.querySelector('#dynamic-element');
if (el) {
driver.defineSteps([
{ element: '#dynamic-element', popover: { title: 'Динамический', description: 'Элемент загружен', position: 'bottom' } }
]);
driver.start();
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
Для страниц, где контент загружается асинхронно (например, через fetch или GraphQL), необходимо:
defineSteps и start после
появления элемента.reset().Пример для Vue:
watch(() => route.name, () => {
driver.reset();
nextTick(() => {
const el = document.querySelector('#new-section');
if (el) {
driver.defineSteps([
{ element: '#new-section', popover: { title: 'Новый раздел', description: 'Описание раздела', position: 'top' } }
]);
driver.start();
}
});
});
Скрытие подсказки по условию: можно добавлять проверку на существование элемента и пропускать шаг:
driver.defineSteps([
{
element: '#optional',
popover: { title: 'Опциональный элемент', description: 'Может отсутствовать' },
onBeforeStep: (step) => {
return !!document.querySelector(step.element);
}
}
]);
Стилизация: Driver.js поддерживает кастомные CSS классы для popover:
driver.defineSteps([
{
element: '#styled',
popover: { title: 'Кастомный стиль', description: 'Используем классы', position: 'bottom', className: 'my-driver-style' }
}
]);
Для SPA важно, чтобы подсказки корректно реагировали на изменение маршрута. В большинстве случаев удобно привязывать шаги к событию изменения маршрута:
router.afterEach((to) => {
driver.reset();
nextTick(() => {
if (to.name === 'Dashboard') {
driver.defineSteps([
{ element: '#dashboard-widget', popover: { title: 'Виджет', description: 'Основная информация', position: 'right' } }
]);
driver.start();
}
});
});
Так обеспечивается корректное управление подсказками на динамически
изменяющемся DOM без ошибок element not found.
MutationObserver
или хуки жизненного цикла фреймворка.onNext, onPrevious)
для динамического изменения шагов в процессе прохождения тура.Эти подходы позволяют создавать интерактивные и надежные пользовательские туры даже в сложных одностраничных приложениях.