События не срабатывают

Shepherd.js предоставляет мощный API для создания интерактивных туров, в том числе управление событиями, которые происходят на различных этапах показа шагов. Иногда разработчики сталкиваются с проблемой: события не срабатывают. Разберём причины и решения этой проблемы.


Основные типы событий

В Shepherd.js события можно разделить на несколько категорий:

  1. События тура Тур генерирует события на глобальном уровне:

    • start — тур начался.
    • complete — тур успешно завершён.
    • cancel — тур был отменён пользователем.
    • show — показывается текущий шаг.
    • hide — шаг скрыт.
  2. События шага Каждый шаг также имеет свои события:

    • show — шаг отображён.
    • hide — шаг скрыт.
    • complete — шаг выполнен.
    • cancel — шаг отменён.
  3. Кнопочные события Shepherd позволяет назначать обработчики на кнопки шага через свойство action. Например:

    buttons: [
      {
        text: 'Далее',
        action: () => {
          console.log('Нажата кнопка Далее');
          return tour.next();
        }
      }
    ]

    Если событие кнопки не срабатывает, важно проверить, что функция возвращает управление (например, return tour.next()).


Причины, по которым события не срабатывают

  1. Элемент ещё не существует в DOM Shepherd.js привязывает шаг к элементу через селектор (attachTo). Если элемент создаётся динамически после инициализации шага, событие show или hide может не сработать. Решение: убедиться, что элемент существует в момент вызова шага, либо использовать tour.addStep после генерации элемента.

    const step = tour.addStep({
      text: 'Пример шага',
      attachTo: { element: '#dynamicElement', on: 'bottom' },
      when: {
        show: () => console.log('Шаг показан')
      }
    });
  2. Неправильное использование свойства when События шага назначаются через объект when внутри конфигурации шага. Ошибки типа:

    when: {
      onShow: () => console.log('Шаг показан') // ❌ неверно
    }

    Ведут к игнорированию события. Правильная запись:

    when: {
      show: () => console.log('Шаг показан') // ✅
    }
  3. Конфликт нескольких обработчиков Если один и тот же шаг многократно инициализируется с разными функциями when, более поздние могут перезаписать предыдущие. Решение: использовать step.on(event, callback) для добавления обработчиков без перезаписи:

    step.on('show', () => console.log('Дополнительный обработчик'));
  4. Возврат промиса или асинхронные действия Shepherd не ожидает асинхронного завершения шага в обработчике. Если функция возвращает промис, событие может показаться не сработавшим. Решение: внутри обработчика использовать async/await корректно, но без ожидания в самой конфигурации шага:

    when: {
      show: async () => {
        await fetch('/api/log');
        console.log('Лог отправлен');
      }
    }
  5. Неправильная инициализация тура Если тур создаётся и сразу вызывается start() до того, как добавлены шаги или назначены события, часть событий может быть пропущена. Решение: всегда сначала определить все шаги, затем вызвать tour.start().


Практические рекомендации

  • Использовать when для всех стандартных событий шага (show, hide, complete, cancel).
  • Добавлять дополнительные обработчики через step.on() для динамических действий.
  • Проверять существование привязываемых элементов DOM перед показом шага.
  • Не полагаться на имена вроде onShow или onHide — библиотека строго использует ключи show и hide.
  • Для кнопок проверять возврат действия (return tour.next()) и избегать асинхронного кода, блокирующего шаг.

Пример корректной настройки шага с событиями

const tour = new Shepherd.Tour({
  defaultStepOptions: {
    scrollTo: true
  }
});

tour.addStep({
  id: 'intro',
  text: 'Добро пожаловать!',
  attachTo: { element: '#intro', on: 'bottom' },
  buttons: [
    {
      text: 'Далее',
      action: () => tour.next()
    }
  ],
  when: {
    show: () => console.log('Шаг intro показан'),
    hide: () => console.log('Шаг intro скрыт')
  }
});

tour.start();

Этот пример демонстрирует правильное использование всех ключевых событий, привязку к DOM-элементу и работу кнопок.


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