Использование с Svelte

Библиотека Driver.js используется для создания интерактивных туров по интерфейсу. В контексте Svelte она легко интегрируется благодаря минималистичной архитектуре и отсутствию необходимости в сложной настройке.

Установка через пакетный менеджер:

npm install driver.js

Подключение стилей (обязательно):

import 'driver.js/dist/driver.css';

Импорт библиотеки в Svelte-компоненте:

import Driver from 'driver.js';

Инициализация экземпляра:

const driver = new Driver();

Основы работы в Svelte-компоненте

Svelte использует реактивную модель, поэтому важно учитывать жизненный цикл компонента. Инициализация Driver.js должна происходить после монтирования DOM.

Использование onMount:

import { onMount } from 'svelte';
import Driver from 'driver.js';
import 'driver.js/dist/driver.css';

let driver;

onMount(() => {
  driver = new Driver({
    animate: true,
    opacity: 0.75,
    padding: 10
  });
});

Определение шагов тура

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

Пример:

const steps = [
  {
    element: '#header',
    popover: {
      title: 'Заголовок',
      description: 'Это основной заголовок страницы',
      position: 'bottom'
    }
  },
  {
    element: '#button',
    popover: {
      title: 'Кнопка',
      description: 'Нажмите для выполнения действия',
      position: 'right'
    }
  }
];

Запуск тура:

driver.defineSteps(steps);
driver.start();

Связка с разметкой Svelte

HTML-разметка:

<h1 id="header">Главная</h1>
<button id="button">Начать</button>

Важно: элементы должны существовать в DOM к моменту запуска тура. В противном случае Driver.js не сможет найти их.


Управление запуском

Часто тур запускается по действию пользователя:

<button on:click={startTour}>Показать тур</button>
function startTour() {
  driver.defineSteps(steps);
  driver.start();
}

Реактивность и обновление шагов

Svelte позволяет динамически изменять шаги через реактивные переменные:

let steps = [];

$: if (dataLoaded) {
  steps = [
    {
      element: '#dynamic',
      popover: {
        title: 'Динамический элемент',
        description: 'Появился после загрузки данных'
      }
    }
  ];
}

Важно повторно вызывать defineSteps, если шаги изменяются:

$: if (steps.length) {
  driver.defineSteps(steps);
}

Работа с асинхронным DOM

В Svelte элементы могут появляться после загрузки данных или условий ({#if}).

Пример:

{#if showElement}
  <div id="dynamic">Контент</div>
{/if}

Запуск тура после появления элемента:

import { tick } from 'svelte';

async function startTour() {
  showElement = true;
  await tick();

  driver.defineSteps(steps);
  driver.start();
}

tick() гарантирует, что DOM обновлён.


Кастомизация интерфейса

Driver.js предоставляет множество настроек:

driver = new Driver({
  className: 'custom-theme',
  animate: true,
  opacity: 0.6,
  allowClose: true,
  overlayClickNext: false
});

Кастомные стили:

.custom-theme .driver-popover {
  background-color: #1e1e1e;
  color: #fff;
}

.custom-theme .driver-popover-title {
  font-weight: bold;
}

Обработка событий

Driver.js поддерживает хуки:

driver = new Driver({
  onHighlightStarted: (element) => {
    console.log('Начало подсветки:', element);
  },
  onDestroyed: () => {
    console.log('Тур завершён');
  }
});

Использование в Svelte:

onMount(() => {
  driver = new Driver({
    onDestroyed: () => {
      completed = true;
    }
  });
});

Управление состоянием тура

Состояние можно хранить в Svelte store:

import { writable } from 'svelte/store';

export const tourCompleted = writable(false);

Обновление состояния:

driver = new Driver({
  onDestroyed: () => {
    tourCompleted.set(true);
  }
});

Повторное использование через action

В Svelte удобно оборачивать логику в action:

export function tour(node, options) {
  const driver = new Driver(options);

  return {
    update(newOptions) {
      driver.setOptions(newOptions);
    },
    destroy() {
      driver.destroy();
    }
  };
}

Использование:

<div use:tour={{ animate: true }}></div>

Работа с маршрутизацией

При использовании SvelteKit важно учитывать смену страниц. Тур можно запускать после навигации:

import { afterNavigate } from '$app/navigation';

afterNavigate(() => {
  driver.start();
});

Ленивый запуск

Чтобы не загружать Driver.js сразу:

let driver;

async function initDriver() {
  const module = await import('driver.js');
  driver = new module.default();
}

Интеграция с пользовательским прогрессом

Сохранение прогресса:

localStorage.setItem('tourCompleted', 'true');

Проверка:

if (!localStorage.getItem('tourCompleted')) {
  driver.start();
}

Ошибки и отладка

Частые проблемы:

Элемент не найден

  • Причина: DOM ещё не обновлён
  • Решение: использовать tick()

Тур не запускается

  • Причина: шаги не определены
  • Проверка: console.log(steps)

Стили не применяются

  • Причина: не подключён CSS
  • Решение: импорт driver.css

Оптимизация

  • Инициализация Driver.js один раз
  • Использование ленивой загрузки
  • Минимизация количества шагов
  • Удаление тура после завершения:
driver.destroy();

Расширенные сценарии

Условные шаги

const steps = [
  user.isAdmin && {
    element: '#admin',
    popover: {
      title: 'Админ-панель'
    }
  }
].filter(Boolean);

Вложенные компоненты

Если элементы находятся в дочерних компонентах:

  • использовать уникальные id
  • запускать тур после их монтирования

Программное управление шагами

driver.moveNext();
driver.movePrevious();
driver.reset();

Архитектурные рекомендации

  • Вынос логики тура в отдельный модуль
  • Использование store для глобального состояния
  • Централизация шагов
  • Контроль запуска через флаги

Пример структуры:

/lib/tour/
  steps.js
  driver.js
  store.js

Пример полной интеграции

import { onMount, tick } from 'svelte';
import Driver from 'driver.js';
import 'driver.js/dist/driver.css';

let driver;

const steps = [
  {
    element: '#title',
    popover: {
      title: 'Заголовок',
      description: 'Описание'
    }
  }
];

onMount(() => {
  driver = new Driver({
    animate: true
  });
});

async function startTour() {
  await tick();
  driver.defineSteps(steps);
  driver.start();
}
<h1 id="title">Пример</h1>
<button on:click={startTour}>Старт</button>

Особенности работы с Svelte

  • отсутствие виртуального DOM упрощает взаимодействие
  • реактивность требует контроля момента запуска
  • tick() — ключевой инструмент синхронизации
  • actions позволяют элегантно инкапсулировать логику