Создание кастомных кнопок

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


Базовая структура кнопок

Кнопки задаются в массиве buttons внутри конфигурации шага:

tour.addStep({
  id: 'step-1',
  text: 'Описание шага',
  buttons: [
    {
      text: 'Далее',
      action: tour.next
    }
  ]
});

Каждая кнопка представляет собой объект со следующими основными свойствами:

  • text — текст кнопки
  • action — функция, выполняемая при нажатии
  • classes — CSS-классы
  • secondary — флаг вторичной кнопки (визуально менее заметной)
  • disabled — состояние неактивности

Управление действиями кнопок

Стандартные действия

Shepherd предоставляет встроенные методы управления туром:

buttons: [
  {
    text: 'Назад',
    action: tour.back
  },
  {
    text: 'Далее',
    action: tour.next
  },
  {
    text: 'Завершить',
    action: tour.complete
  }
]

Ключевые методы:

  • tour.next() — переход к следующему шагу
  • tour.back() — возврат к предыдущему
  • tour.cancel() — отмена тура
  • tour.complete() — завершение

Кастомные функции

Кнопка может выполнять произвольный код:

buttons: [
  {
    text: 'Проверить',
    action: function() {
      console.log('Проверка выполнена');
      tour.next();
    }
  }
]

Контекст this внутри функции ссылается на текущий шаг:

action: function() {
  console.log(this.id);
}

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

Отключение кнопок

buttons: [
  {
    text: 'Далее',
    action: tour.next,
    disabled: true
  }
]

Динамическое изменение:

const step = tour.getById('step-1');
step.updateStepOptions({
  buttons: [
    {
      text: 'Далее',
      action: tour.next,
      disabled: false
    }
  ]
});

Условная логика

buttons: [
  {
    text: 'Продолжить',
    action: function() {
      if (document.querySelector('#agree').checked) {
        tour.next();
      } else {
        alert('Необходимо согласие');
      }
    }
  }
]

Стилизация кнопок

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

buttons: [
  {
    text: 'Далее',
    action: tour.next,
    classes: 'btn btn-primary'
  },
  {
    text: 'Отмена',
    action: tour.cancel,
    classes: 'btn btn-secondary',
    secondary: true
  }
]

Свойство secondary добавляет встроенный стиль Shepherd для вторичных кнопок.


Полная кастомизация через CSS

.shepherd-button.custom-next {
  background-color: #4CAF50;
  color: white;
  border-radius: 6px;
}

.shepherd-button.custom-cancel {
  background-color: transparent;
  color: #999;
}
buttons: [
  {
    text: 'Далее',
    action: tour.next,
    classes: 'custom-next'
  },
  {
    text: 'Пропустить',
    action: tour.cancel,
    classes: 'custom-cancel'
  }
]

Асинхронные действия кнопок

Кнопки могут выполнять асинхронные операции:

buttons: [
  {
    text: 'Загрузить',
    action: async function() {
      const data = await fetch('/api/data');
      const result = await data.json();

      console.log(result);
      tour.next();
    }
  }
]

Обработка состояний загрузки

buttons: [
  {
    text: 'Отправить',
    action: async function() {
      const button = this.el.querySelector('.shepherd-button');
      button.disabled = true;
      button.innerText = 'Загрузка...';

      await new Promise(resolve => setTimeout(resolve, 2000));

      tour.next();
    }
  }
]

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

Частый сценарий — комбинирование кнопок:

buttons: [
  {
    text: 'Назад',
    action: tour.back,
    secondary: true
  },
  {
    text: 'Пропустить',
    action: tour.cancel,
    secondary: true
  },
  {
    text: 'Далее',
    action: tour.next
  }
]

Порядок в массиве определяет порядок отображения.


Кнопки с контекстной логикой

Разные действия на разных шагах

tour.addStep({
  id: 'step-final',
  text: 'Финальный шаг',
  buttons: [
    {
      text: 'Готово',
      action: function() {
        console.log('Тур завершён');
        tour.complete();
      }
    }
  ]
});

Переключение поведения кнопки

let isValid = false;

buttons: [
  {
    text: 'Продолжить',
    action: function() {
      if (!isValid) {
        alert('Ошибка');
        return;
      }

      tour.next();
    }
  }
]

Использование стрелочных функций

Важно учитывать различие контекста:

{
  text: 'Далее',
  action: () => {
    tour.next();
  }
}

Стрелочные функции не имеют собственного this, поэтому доступ к шагу через this невозможен. Для доступа к текущему шагу используется обычная функция:

action: function() {
  console.log(this);
}

Добавление и изменение кнопок на лету

Обновление шага

const step = tour.getById('step-1');

step.updateStepOptions({
  buttons: [
    {
      text: 'Новое действие',
      action: tour.next
    }
  ]
});

Удаление кнопок

step.updateStepOptions({
  buttons: []
});

Интеграция с внешними событиями

Кнопка может взаимодействовать с DOM:

buttons: [
  {
    text: 'Открыть меню',
    action: function() {
      document.querySelector('#menu').classList.add('open');
      tour.next();
    }
  }
]

Расширенные сценарии

Валидация формы перед переходом

buttons: [
  {
    text: 'Продолжить',
    action: function() {
      const input = document.querySelector('#email');

      if (!input.value.includes('@')) {
        input.classList.add('error');
        return;
      }

      tour.next();
    }
  }
]

Кнопки с подтверждением

buttons: [
  {
    text: 'Удалить',
    action: function() {
      if (confirm('Вы уверены?')) {
        console.log('Удалено');
        tour.next();
      }
    }
  }
]

Лучшие практики

Минимизация количества кнопок Избыточное количество элементов снижает понятность интерфейса.

Явные действия Названия кнопок должны отражать результат: «Сохранить», «Пропустить», «Завершить».

Разделение первичных и вторичных действий Использование secondary помогает визуально выделить основной путь.

Обработка ошибок Любое пользовательское действие должно предусматривать возможные ошибки.

Асинхронная безопасность При работе с API необходимо блокировать повторные нажатия.


Типичные ошибки

Использование стрелочных функций с this

action: () => {
  console.log(this); // undefined или глобальный объект
}

Отсутствие перехода между шагами

action: function() {
  console.log('Нажато'); // нет tour.next()
}

Жёсткая привязка к DOM

document.querySelector('#nonexistent')

Гибкость архитектуры кнопок

Система кнопок в Shepherd позволяет:

  • внедрять бизнес-логику прямо в тур
  • синхронизировать UI с состоянием приложения
  • строить сложные сценарии взаимодействия
  • адаптировать поведение под пользователя

Кнопки перестают быть просто элементом навигации и становятся полноценным инструментом управления пользовательским сценарием.