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

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


Хранение текущего шага

Каждый тур в Shepherd.js состоит из последовательности шагов, каждый из которых имеет уникальный идентификатор (id). Для сохранения прогресса удобно хранить текущий шаг в локальном хранилище браузера (localStorage) или в базе данных на сервере.

const tour = new Shepherd.Tour({
  defaultStepOptions: {
    cancelIcon: { enabled: true },
    scrollTo: { beh * avior: 'smooth', block: 'center' }
  }
});

tour.addStep({
  id: 'step-1',
  text: 'Это первый шаг тура.',
  attachTo: { element: '.feature1', on: 'bottom' },
  buttons: [
    {
      text: 'Далее',
      action: () => {
        saveProgress('step-2');
        tour.next();
      }
    }
  ]
});

function saveProgress(stepId) {
  localStorage.setItem('tourProgress', stepId);
}

function getSavedProgress() {
  return localStorage.getItem('tourProgress');
}

В этом примере после нажатия кнопки “Далее” вызывается функция saveProgress, которая сохраняет идентификатор следующего шага. При повторном открытии страницы можно прочитать значение и возобновить тур с нужного шага.


Возобновление тура с сохраненного шага

Для корректного возобновления нужно сначала проверить наличие сохраненного шага и запустить тур с него. Shepherd.js предоставляет метод show() для конкретного шага по id.

const savedStep = getSavedProgress();

if (savedStep) {
  tour.start();
  tour.show(savedStep);
} else {
  tour.start();
}

Важно учитывать, что tour.start() всегда запускает тур с первого шага, поэтому метод show(savedStep) необходим для перехода к нужной позиции.


Автоматическое сохранение прогресса при переходе между шагами

Для более автоматизированного управления прогрессом можно использовать событие active каждого шага. Это позволяет сохранять состояние без привязки к кнопкам.

tour.on('show', () => {
  const currentStep = tour.currentStep.id;
  saveProgress(currentStep);
});

Событие show срабатывает при отображении любого шага, а currentStep.id позволяет определить текущий идентификатор шага и обновить сохраненные данные.


Интеграция с серверной логикой

В приложениях, где пользователь может заходить с разных устройств, локальное хранилище не подходит. В этом случае прогресс можно отправлять на сервер через API:

function saveProgressToServer(stepId) {
  fetch('/api/save-tour-progress', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ step: stepId })
  });
}

tour.on('show', () => {
  saveProgressToServer(tour.currentStep.id);
});

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


Учет завершения тура

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

tour.on('complete', () => {
  localStorage.setItem('tourCompleted', 'true');
});

tour.on('cancel', () => {
  localStorage.removeItem('tourProgress');
});

При запуске приложения проверка этого флага позволит пропускать тур для пользователей, которые уже завершили его:

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

Продвинутая логика сохранения

Для сложных интерфейсов можно комбинировать несколько подходов:

  • Множественные туры: хранить прогресс по каждому туру отдельно (tour1Step, tour2Step).
  • Условные шаги: пропускать шаги, если пользователь уже выполнял действия, к которым они привязаны.
  • Временные шаги: сохранять не только текущий шаг, но и контекст страницы, например выбранные вкладки или открытые модальные окна.
function saveTourContext(stepId, context) {
  localStorage.setItem('tourProgress', JSON.stringify({ step: stepId, context }));
}

function getTourContext() {
  const data = localStorage.getItem('tourProgress');
  return data ? JSON.parse(data) : null;
}

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


Рекомендации по структуре шагов

  1. Присваивать каждому шагу уникальный id.
  2. Минимизировать зависимость шагов от конкретных событий DOM, чтобы тур был устойчив к изменениям интерфейса.
  3. Обрабатывать события complete и cancel для корректного обновления состояния.
  4. Использовать серверное хранение для многоустройственных приложений.

Эти методы позволяют Shepherd.js не только создавать визуальные туры, но и управлять прогрессом пользователя, обеспечивая плавный и персонализированный опыт даже при перезапуске приложения.