Обработка переходов между страницами

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

Ключевая проблема — при смене страницы происходит перезагрузка DOM, и экземпляр Intro.js уничтожается. Поэтому требуется сохранять текущее состояние (шаг, прогресс, контекст) во внешнем хранилище.


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

Основной подход — фиксировать номер текущего шага перед переходом:

const intro = introJs();

intro.onbeforechange(function(targetElement) {
    const step = this._currentStep;
    localStorage.setItem('introStep', step);
});

Свойство _currentStep содержит индекс шага (начиная с 0). Его можно сохранять в:

  • localStorage — для простоты
  • sessionStorage — если важно ограничить сессию
  • cookies — при необходимости серверной синхронизации

Инициализация тура на новой странице

После загрузки следующей страницы необходимо восстановить сохранённый шаг:

const savedStep = parseInt(localStorage.getItem('introStep'), 10);

if (!isNaN(savedStep)) {
    const intro = introJs();

    intro.start().goToStep(savedStep + 1);
}

Важно учитывать, что метод goToStep принимает значение, начиная с 1.


Синхронизация шагов между страницами

При многостраничном туре необходимо:

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

Пример настройки шагов:

introJs().setOptions({
    steps: [
        {
            element: '#header',
            intro: 'Заголовок страницы'
        },
        {
            element: '#menu',
            intro: 'Основное меню'
        }
    ]
});

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


Перенаправление внутри тура

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

intro.onafterchange(function(targetElement) {
    if (this._currentStep === 2) {
        window.location.href = '/next-page.html';
    }
});

Перед переходом важно:

  • сохранить текущий шаг
  • возможно, сохранить дополнительные данные (например, состояние интерфейса)

Продолжение тура после загрузки страницы

На новой странице необходимо:

  1. Проверить наличие сохранённого шага
  2. Инициализировать Intro.js
  3. Перейти к нужному шагу
window.onl oad = function() {
    const step = localStorage.getItem('introStep');

    if (step !== null) {
        introJs().start().goToStep(parseInt(step, 10) + 1);
    }
};

Очистка состояния после завершения

После завершения тура необходимо удалить сохранённые данные:

intro.oncomplete(function() {
    localStorage.removeItem('introStep');
});

intro.onexit(function() {
    localStorage.removeItem('introStep');
});

Это предотвращает повторное автоматическое восстановление тура.


Работа с динамическими элементами

При переходе между страницами элементы могут:

  • загружаться асинхронно
  • отсутствовать в момент старта тура

В таких случаях необходимо задержать запуск:

setTimeout(function() {
    introJs().start().goToStep(savedStep + 1);
}, 500);

Более надёжный вариант — отслеживание появления элемента:

function waitForElement(selector, callback) {
    const interval = setInterval(() => {
        if (document.querySelector(selector)) {
            clearInterval(interval);
            callback();
        }
    }, 100);
}

Использование query-параметров

Альтернативный способ передачи состояния — через URL:

/next-page.html?step=2

Получение параметра:

const params = new URLSearchParams(window.location.search);
const step = parseInt(params.get('step'), 10);

Преимущества:

  • прозрачность
  • удобство отладки
  • отсутствие зависимости от хранилищ

Комбинирование с роутингом SPA

В одностраничных приложениях (React, Vue, Angular) переходы не перезагружают страницу, но DOM изменяется. В этом случае:

  • сохраняется экземпляр Intro.js
  • требуется вручную управлять шагами

Пример:

router.afterEach(() => {
    const step = localStorage.getItem('introStep');

    if (step !== null) {
        introJs().goToStep(parseInt(step, 10) + 1);
    }
});

Учет различий DOM между страницами

При несовпадении элементов возможны ошибки:

  • шаг не может найти элемент
  • тур прерывается

Решения:

  1. Использование intro: '...' без element
  2. Проверка существования элемента:
steps: [
    document.querySelector('#menu') ? {
        element: '#menu',
        intro: 'Меню'
    } : {
        intro: 'Меню отсутствует на этой странице'
    }
]

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

Для более сложных сценариев можно хранить:

  • текущий шаг
  • общее количество шагов
  • посещённые страницы

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

const tourState = {
    step: 2,
    page: '/dashboard',
    completed: false
};

localStorage.setItem('tourState', JSON.stringify(tourState));

Прерывание и возобновление тура

Пользователь может прервать тур и вернуться позже. Для этого:

  • состояние сохраняется при onexit
  • при повторном входе тур продолжается
intro.onexit(function() {
    localStorage.setItem('introStep', this._currentStep);
});

Обработка ошибок и отказоустойчивость

Рекомендуется учитывать:

  • отсутствие сохранённых данных
  • некорректные значения шага
  • изменение структуры интерфейса

Проверка:

if (step >= 0 && step < steps.length) {
    introJs().goToStep(step + 1);
} else {
    localStorage.removeItem('introStep');
}

Архитектурный подход

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

class TourManager {
    static saveStep(step) {
        localStorage.setItem('introStep', step);
    }

    static getStep() {
        return parseInt(localStorage.getItem('introStep'), 10);
    }

    static clear() {
        localStorage.removeItem('introStep');
    }
}

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

intro.onbeforechange(function() {
    TourManager.saveStep(this._currentStep);
});

Ключевые принципы

  • состояние тура должно храниться вне Intro.js
  • переходы должны быть контролируемыми
  • восстановление должно быть безопасным
  • структура шагов должна быть согласованной

Грамотная обработка переходов превращает Intro.js из простой библиотеки подсказок в полноценный инструмент обучения пользователя внутри многостраничного интерфейса.