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

В библиотеке Shepherd.js любая подсказка (тур) привязывается к DOM-элементу через опцию attachTo. Если указанный элемент отсутствует на странице, стандартное поведение Shepherd — попытка найти селектор и, не найдя его, вызвать ошибку в консоли или пропустить шаг. Управление ситуациями, когда элемент не найден, критично для стабильности интерактивных туров.

Опция attachTo и её структура

attachTo задаётся в виде объекта:

attachTo: {
  element: '.selector', // CSS-селектор или HTMLElement
  on: 'bottom'          // положение подсказки относительно элемента
}

Если элемент по селектору отсутствует, Shepherd не сможет корректно отобразить шаг. Это может привести к визуальным артефактам и остановке тура.

Проверка наличия элемента перед созданием шага

Самый надёжный подход — проверять существование элемента заранее:

const target = document.querySelector('.selector');

if (target) {
  tour.addStep({
    id: 'step1',
    text: 'Это описание шага',
    attachTo: { element: target, on: 'bottom' }
  });
}

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

Использование beforeShowPromise для динамических элементов

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

tour.addStep({
  id: 'dynamic-step',
  text: 'Элемент появляется с задержкой',
  attachTo: { element: '.dynamic-element', on: 'top' },
  beforeShowPromise: () => {
    return new Promise((resolve, reject) => {
      const interval = setInterval(() => {
        const el = document.querySelector('.dynamic-element');
        if (el) {
          clearInterval(interval);
          resolve();
        }
      }, 100);
      setTimeout(() => {
        clearInterval(interval);
        reject();
      }, 5000);
    });
  }
});

Здесь Shepherd ждёт, пока элемент появится, и только после этого отображает шаг. В противном случае шаг отклоняется через reject(), предотвращая зависание тура.

Использование when для условного отображения шага

Shepherd поддерживает объект when, который позволяет управлять событиями шага, в том числе пропускать шаг, если элемент не найден:

tour.addStep({
  id: 'conditional-step',
  text: 'Проверка наличия элемента',
  attachTo: { element: '.maybe-exists', on: 'right' },
  when: {
    show: function() {
      const el = document.querySelector('.maybe-exists');
      if (!el) {
        this.hide(); // Пропустить шаг
      }
    }
  }
});

Использование when.show позволяет интегрировать логику проверки прямо в жизненный цикл шага.

Настройка fallback-положения

Если элемент может быть временно недоступен, можно задавать альтернативное положение через кастомную проверку:

const stepElement = document.querySelector('.primary-element');
tour.addStep({
  id: 'fallback-step',
  text: 'Подсказка с запасным элементом',
  attachTo: { 
    element: stepElement || '.fallback-element', 
    on: stepElement ? 'bottom' : 'top' 
  }
});

Таким образом, подсказка всегда привязывается к существующему элементу, а визуальный опыт остаётся непрерывным.

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

Shepherd.js позволяет обрабатывать ошибки через глобальные события тура:

tour.on('error', (error) => {
  console.warn('Shepherd error:', error);
});

Это полезно для логирования и диагностики, если шаги не отображаются из-за отсутствующих элементов.

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

  • Минимизировать шаги, зависящие от нестабильных элементов. Если элемент часто отсутствует, лучше пропустить шаг или использовать альтернативный элемент.
  • Динамическая проверка через beforeShowPromise. Для SPA и ленивой загрузки это основной инструмент.
  • Fallback-элементы повышают устойчивость тура и предотвращают пустые подсказки.
  • Логирование ошибок помогает отслеживать проблемы при разработке и эксплуатации.

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