Селекторы элементов

В библиотеке Shepherd.js селекторы являются ключевым механизмом привязки шагов тура к конкретным элементам интерфейса. Каждый шаг (step) описывает, к какому DOM-элементу он должен «прикрепиться», чтобы подсказка корректно отображалась рядом с нужной частью страницы.

Основное свойство, отвечающее за это — attachTo. Оно определяет:

  • целевой элемент
  • позицию тултипа относительно него

Свойство attachTo

Структура:

attachTo: {
  element: 'селектор',
  on: 'позиция'
}
  • element — CSS-селектор или DOM-элемент
  • on — положение подсказки относительно элемента

Пример:

{
  id: 'step-1',
  text: 'Это кнопка отправки формы',
  attachTo: {
    element: '.submit-button',
    on: 'bottom'
  }
}

Поддерживаемые типы селекторов

Shepherd.js использует стандартные CSS-селекторы, поэтому доступны все привычные варианты:

1. По классу

element: '.menu-item'

2. По id

element: '#main-header'

3. По тегу

element: 'button'

4. Сложные селекторы

element: '.form-container input[type="email"]'

5. Псевдоклассы

element: 'li:first-child'

Передача DOM-элемента напрямую

Вместо строки-селектора можно передать уже найденный элемент:

element: document.querySelector('.submit-button')

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

  • исключается повторный поиск в DOM
  • повышается производительность при сложных интерфейсах

Недостаток:

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

Динамические селекторы

В сложных интерфейсах элементы могут появляться не сразу (например, после AJAX-запроса или открытия модального окна). В таких случаях селектор может быть функцией:

attachTo: {
  element: () => document.querySelector('.dynamic-element'),
  on: 'right'
}

Это позволяет:

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

Обработка отсутствующих элементов

Если элемент не найден, Shepherd.js:

  • не сможет корректно отобразить шаг
  • может пропустить позиционирование

Рекомендуемые подходы:

Проверка перед запуском тура

if (document.querySelector('.target')) {
  tour.start();
}

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

{
  id: 'step-async',
  text: 'Динамический элемент',
  attachTo: {
    element: '.async-element',
    on: 'left'
  },
  beforeShowPromise: function() {
    return new Promise(resolve => {
      setTimeout(resolve, 500);
    });
  }
}

Позиционирование (on)

Свойство on определяет, где будет отображаться подсказка:

  • top
  • bottom
  • left
  • right
  • комбинации: top-start, bottom-end и др.

Пример:

attachTo: {
  element: '.profile-avatar',
  on: 'right-start'
}

Работа с несколькими совпадениями

Если селектор находит несколько элементов:

element: '.item'

Shepherd.js использует первый найденный элемент (querySelector).

Для выбора конкретного:

element: '.item:nth-child(3)'

или:

element: document.querySelectorAll('.item')[2]

Лучшие практики выбора селекторов

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

Предпочтительно:

element: '#submit-btn'

Менее надежно:

element: 'button'

2. Избегание зависимостей от структуры DOM

Плохо:

element: '.container > div > ul > li:nth-child(2)'

Хорошо:

element: '.menu-item-settings'

3. Использование data-атрибутов

Наиболее устойчивый подход:

<button data-tour="submit">Отправить</button>
element: '[data-tour="submit"]'

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

  • независимость от CSS и верстки
  • стабильность при рефакторинге

Селекторы и SPA-приложения

В одностраничных приложениях (React, Vue, Angular):

  • элементы могут перерисовываться
  • DOM-узлы могут исчезать

Рекомендации:

Использование функций

element: () => document.querySelector('[data-tour="step1"]')

Привязка к состоянию

Запуск тура после рендера:

setTimeout(() => tour.start(), 0);

или через lifecycle-хуки (например, useEffect в React)


Селекторы внутри модальных окон

Если элемент находится внутри модального окна:

  • убедиться, что окно открыто до показа шага
  • использовать beforeShowPromise
beforeShowPromise: () => {
  return new Promise(resolve => {
    openModal();
    setTimeout(resolve, 300);
  });
}

Селекторы и прокрутка страницы

Если элемент вне зоны видимости:

  • Shepherd автоматически прокручивает страницу
  • используется scrollTo

Настройка:

scrollTo: true

или более гибко:

scrollTo: {
  beh * avior: 'smooth',
  block: 'center'
}

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

1. Селектор не существует

element: '.non-existent'

Результат: шаг не отображается корректно


2. Элемент скрыт (display: none)

Shepherd не может корректно позиционировать подсказку


3. Элемент появляется позже

Решение:

  • beforeShowPromise
  • функция-селектор

4. Изменение DOM между шагами

Если интерфейс меняется:

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

Отладка селекторов

Полезные методы:

Проверка в консоли

document.querySelector('.selector')

Подсветка элемента

document.querySelector('.selector').style.outline = '2px solid red';

Итоговые рекомендации

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

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