Пропуск необязательных шагов

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

Библиотека Intro.js поддерживает несколько подходов к реализации пропуска шагов:

  • на уровне конфигурации
  • динамически во время выполнения
  • через пользовательский интерфейс (кнопки, чекбоксы, условия)
  • с использованием API событий

Статическое исключение шагов

Наиболее простой способ — не включать необязательные шаги в массив steps.

introJs().setOptions({
  steps: [
    {
      intro: "Добро пожаловать!"
    },
    {
      element: document.querySelector('#main-feature'),
      intro: "Основной функционал"
    }
    // необязательные шаги просто не добавлены
  ]
});

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


Использование пользовательских флагов

Часто используется логика с флагами, определяющими необходимость отображения шага.

const showAdvanced = false;

const steps = [
  {
    intro: "Базовое описание"
  },
  showAdvanced && {
    element: document.querySelector('#advanced'),
    intro: "Дополнительные возможности"
  }
].filter(Boolean);

introJs().setOptions({ steps }).start();

Особенности:

  • шаг добавляется только при выполнении условия
  • filter(Boolean) удаляет false из массива
  • позволяет гибко управлять набором шагов до запуска тура

Динамический пропуск во время выполнения

Intro.js предоставляет API для управления переходами между шагами.

Метод goToStep

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

introJs().goToStep(5);

Метод nextStep

Можно вызывать вручную, пропуская текущий шаг:

introJs().nextStep();

Пропуск через обработчики событий

Одним из наиболее мощных инструментов является использование событий Intro.js.

Событие onbeforechange

Срабатывает перед отображением шага:

introJs().onbeforechange(function(targetElement) {
  if (targetElement.id === 'optional-step') {
    this.nextStep();
  }
});

Здесь происходит:

  • проверка идентификатора элемента
  • условное пропускание шага
  • автоматический переход к следующему

Управление через пользовательский интерфейс

В реальных приложениях часто требуется дать пользователю выбор: проходить шаг или пропустить его.

Кнопка “Пропустить”

introJs().onafterchange(function() {
  const skipBtn = document.createElement('button');
  skipBtn.innerText = "Пропустить";
  
  skipBtn.oncl ick = () => {
    introJs().nextStep();
  };

  document.querySelector('.introjs-tooltipbuttons').appendChild(skipBtn);
});

Особенности:

  • кнопка добавляется в панель управления
  • позволяет пропустить текущий шаг вручную
  • не нарушает структуру тура

Групповой пропуск шагов

Иногда требуется пропустить не один, а несколько шагов.

Пример логики

introJs().onbeforechange(function(targetElement) {
  const skipGroup = ['step-3', 'step-4', 'step-5'];

  if (skipGroup.includes(targetElement.id)) {
    this.goToStep(6);
  }
});

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

  • централизованное управление
  • удобно для блоков шагов (например, “расширенные настройки”)

Условный пропуск на основе состояния приложения

Пропуск может зависеть от:

  • роли пользователя
  • наличия данных
  • состояния интерфейса
const isAdmin = false;

introJs().onbeforechange(function(targetElement) {
  if (targetElement.id === 'admin-panel' && !isAdmin) {
    this.nextStep();
  }
});

Пропуск шагов с отсутствующими элементами

Если элемент отсутствует в DOM, шаг становится бесполезным.

introJs().onbeforechange(function(targetElement) {
  if (!targetElement) {
    this.nextStep();
  }
});

Или более явно:

const element = document.querySelector('#dynamic-element');

if (!element) {
  // шаг не добавляется
}

Использование кастомных атрибутов

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

<div id="feature" data-optional="true"></div>
introJs().onbeforechange(function(targetElement) {
  if (targetElement.dataset.optional === "true") {
    this.nextStep();
  }
});

Временное отключение шагов

Иногда шаг должен отображаться только один раз.

const seenSteps = new Set();

introJs().onbeforechange(function(targetElement) {
  if (seenSteps.has(targetElement.id)) {
    this.nextStep();
  } else {
    seenSteps.add(targetElement.id);
  }
});

Пропуск с сохранением состояния

Для сохранения выбора пользователя используется localStorage.

const skipAdvanced = localStorage.getItem('skipAdvanced') === 'true';

introJs().onbeforechange(function(targetElement) {
  if (targetElement.id === 'advanced' && skipAdvanced) {
    this.nextStep();
  }
});

Запись значения:

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

Полное отключение шагов через конфигурацию

Можно управлять шагами централизованно:

function createSteps(options) {
  const steps = [
    { intro: "Начало" }
  ];

  if (options.includeAdvanced) {
    steps.push({
      element: '#advanced',
      intro: "Расширенные функции"
    });
  }

  return steps;
}

introJs().setOptions({
  steps: createSteps({ includeAdvanced: false })
});

Обработка пропуска при возврате назад

Важно учитывать поведение при переходе назад:

introJs().onbeforechange(function(targetElement) {
  const skipped = ['step-3'];

  if (skipped.includes(targetElement.id)) {
    this.nextStep();
  }
});

Без дополнительной логики шаг может снова появиться при возврате.


Частые ошибки

Бесконечный цикл переходов

this.nextStep();

Если условие всегда истинно — произойдет зацикливание.

Неверная индексация шагов

Метод goToStep использует индексацию с 1, а не с 0.

Отсутствие проверки элемента

Попытка пропуска без проверки может вызвать ошибки:

if (!targetElement) return;

Рекомендации по архитектуре

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

Сценарии применения

Обучающие туры:

  • пропуск продвинутых функций для новичков

Административные панели:

  • скрытие шагов для обычных пользователей

Адаптивные интерфейсы:

  • пропуск шагов для отсутствующих элементов

Персонализация:

  • запоминание предпочтений пользователя

Комбинированный подход

Наиболее эффективный вариант — сочетание методов:

  1. предварительная фильтрация шагов
  2. динамическая проверка через события
  3. пользовательский контроль (кнопки)
  4. сохранение состояния
const steps = getSteps().filter(step => !step.optional);

introJs()
  .setOptions({ steps })
  .onbeforechange(function(targetElement) {
    if (shouldSkip(targetElement)) {
      this.nextStep();
    }
  })
  .start();

Такой подход обеспечивает:

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