Обработка ошибок валидации

Shepherd.js предоставляет гибкую систему создания интерактивных туров по веб-приложению. Одним из ключевых аспектов при построении тура является управление ситуациями, когда шаг не может корректно отобразиться, либо элементы DOM отсутствуют или недоступны. Обработка ошибок валидации позволяет обеспечивать стабильность работы тура и корректное информирование пользователя о проблемах.


Валидация целевых элементов

Каждый шаг Shepherd.js имеет свойство attachTo, определяющее элемент DOM, к которому шаг будет прикреплён:

attachTo: {
  element: '#elementId',
  on: 'bottom'
}

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

const targetElement = document.querySelector('#elementId');
if (targetElement) {
  tour.addStep({
    title: 'Пример шага',
    text: 'Описание шага',
    attachTo: { element: '#elementId', on: 'bottom' }
  });
} else {
  console.warn('Элемент для шага не найден: #elementId');
}

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


Обработка ошибок при запуске тура

Метод tour.start() может столкнуться с проблемами, если один из шагов некорректно сконфигурирован. Shepherd.js генерирует события, которые позволяют отслеживать ошибки:

tour.on('error', (error) => {
  console.error('Произошла ошибка в туре:', error);
});

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

tour.steps.forEach((step, index) => {
  if (!document.querySelector(step.options.attachTo?.element)) {
    console.error(`Шаг ${index} недоступен, элемент не найден`);
  }
});

Валидация параметров шага

Shepherd.js требует корректного указания свойств шага: title, text, buttons и attachTo. Неправильное использование этих параметров может привести к непредсказуемому поведению. Примеры валидации:

  • Проверка текста шага:
if (typeof step.options.text !== 'string' || !step.options.text.trim()) {
  console.warn('Текст шага отсутствует или некорректен');
}
  • Проверка кнопок:
if (!Array.isArray(step.options.buttons) || step.options.buttons.length === 0) {
  console.warn('У шага отсутствуют кнопки управления');
}
  • Проверка attachTo:
if (!step.options.attachTo || !document.querySelector(step.options.attachTo.element)) {
  console.warn('Невозможно прикрепить шаг, элемент отсутствует');
}

Обработка ошибок динамических элементов

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

function waitForElement(selector, callback, timeout = 5000) {
  const start = Date.now();
  const interval = setInterval(() => {
    const element = document.querySelector(selector);
    if (element) {
      clearInterval(interval);
      callback(element);
    } else if (Date.now() - start > timeout) {
      clearInterval(interval);
      console.error(`Элемент ${selector} не появился в DOM`);
    }
  }, 100);
}

waitForElement('#dynamicElement', (el) => {
  tour.addStep({
    title: 'Динамический шаг',
    text: 'Шаг прикреплён к динамическому элементу',
    attachTo: { element: '#dynamicElement', on: 'top' }
  });
});

Глобальные обработчики ошибок шагов

Для централизованного управления ошибками удобно создавать вспомогательную функцию, которая проверяет корректность всех шагов перед запуском:

function validateTourSteps(tour) {
  tour.steps.forEach((step, index) => {
    if (!step.options.title || !step.options.text) {
      console.error(`Шаг ${index} имеет пустые title или text`);
    }
    if (step.options.attachTo && !document.querySelector(step.options.attachTo.element)) {
      console.error(`Элемент для шага ${index} не найден: ${step.options.attachTo.element}`);
    }
    if (!Array.isArray(step.options.buttons) || step.options.buttons.length === 0) {
      console.warn(`Шаг ${index} не имеет кнопок управления`);
    }
  });
}

validateTourSteps(tour);
tour.start();

Такой подход обеспечивает предсказуемое поведение и минимизирует вероятность сбоев.


Логирование и оповещение

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

function showError(message) {
  const errorBox = document.createElement('div');
  errorBox.textContent = message;
  errorBox.style.position = 'fixed';
  errorBox.style.bottom = '10px';
  errorBox.style.right = '10px';
  errorBox.style.background = 'red';
  errorBox.style.color = 'white';
  errorBox.style.padding = '8px';
  errorBox.style.zIndex = '9999';
  document.body.appendChild(errorBox);
  setTimeout(() => errorBox.remove(), 5000);
}

В случае недоступного шага или отсутствующего элемента можно вызывать showError для информирования пользователя.


Использование try/catch при выполнении действий

Иногда внутри шага выполняются функции, которые могут выбросить исключение. Shepherd.js позволяет использовать advanceOn и пользовательские обработчики, которые нужно оборачивать в try/catch:

tour.addStep({
  title: 'Шаг с действием',
  text: 'Пример обработки ошибок внутри шага',
  buttons: [
    {
      text: 'Далее',
      action: () => {
        try {
          performAction(); // функция, которая может выбросить ошибку
          tour.next();
        } catch (error) {
          console.error('Ошибка выполнения действия шага:', error);
          showError('Не удалось выполнить действие шага');
        }
      }
    }
  ]
});

Рекомендации по безопасной валидации

  • Всегда проверять наличие целевого элемента перед добавлением шага.
  • Использовать централизованную функцию проверки шагов перед запуском тура.
  • Оборачивать критические функции в try/catch.
  • Для динамических элементов использовать отложенное выполнение или MutationObserver.
  • Логировать ошибки и предупреждения в консоль, а при необходимости – уведомлять пользователя через UI.

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