Shepherd.js — библиотека для создания интерактивных туров по веб-приложению. Одной из ключевых возможностей является ленивая загрузка контента, которая позволяет динамически подгружать элементы интерфейса только в момент их использования в туре. Это повышает производительность и упрощает управление сложными интерфейсами.
Ленивая загрузка достигается за счёт передачи в конфигурацию шагов
функции, которая возвращает содержимое только при активации
шага. Вместо статического HTML или заранее подготовленных
DOM-элементов, используется функция text или
attachTo, которая вычисляется в момент показа шага.
const tour = new Shepherd.Tour({
defaultStepOptions: {
scrollTo: true,
classes: 'shepherd-theme-arrows'
}
});
tour.addStep({
id: 'step-dynamic',
text: () => {
const dynamicContent = document.querySelector('#dynamic-element');
if (dynamicContent) {
return `Содержимое элемента: ${dynamicContent.innerText}`;
}
return 'Элемент ещё не загружен';
},
attachTo: {
element: () => document.querySelector('#dynamic-element'),
on: 'bottom'
}
});
tour.start();
Ключевые моменты:
text может быть функцией, возвращающей строку или
HTML-контент.attachTo.element поддерживает функцию, возвращающую
DOM-элемент, что позволяет обращаться к элементам, которые появляются на
странице только после асинхронной загрузки.null или undefined из функции
element приведёт к пропуску шага или задержке его показа до
момента появления элемента.В реальных приложениях элементы часто загружаются через AJAX или отображаются после действий пользователя. Для корректной работы шага с ленивой загрузкой рекомендуется использовать проверку существования элемента с повторением до момента появления.
function waitForElement(selector, timeout = 3000) {
return new Promise((resolve, reject) => {
const interval = 50;
let elapsed = 0;
const check = setInterval(() => {
const el = document.querySelector(selector);
if (el) {
clearInterval(check);
resolve(el);
}
elapsed += interval;
if (elapsed >= timeout) {
clearInterval(check);
reject(new Error('Элемент не найден'));
}
}, interval);
});
}
tour.addStep({
id: 'async-step',
text: async () => {
const element = await waitForElement('#async-element');
return `Загруженный элемент содержит: ${element.innerText}`;
},
attachTo: {
element: async () => await waitForElement('#async-element'),
on: 'top'
}
});
Особенности:
text,
так и в attachTo.element.В приложениях на Vue, React или Angular компоненты часто рендерятся только после изменения состояния. Shepherd.js поддерживает динамическое получение элементов в момент показа шага, что делает библиотеку совместимой с современными SPA.
tour.addStep({
id: 'react-step',
text: () => {
const componentNode = document.querySelector('.react-component');
return componentNode ? 'Компонент готов к использованию' : 'Компонент ещё не загружен';
},
attachTo: {
element: () => document.querySelector('.react-component'),
on: 'right'
},
when: {
show: () => console.log('Шаг показан')
}
});
Рекомендации:
element и text
вместо статических селекторов.MutationObserver) для мгновенного реагирования на
появление элементов.scrollTo: true, чтобы автоматически
прокручивать страницу к лениво загруженным элементам.tour.addStep({
id: 'conditional-step',
text: () => document.querySelector('#special-element')
? 'Элемент доступен'
: 'Элемент недоступен',
attachTo: {
element: () => document.querySelector('#special-element'),
on: 'bottom'
}
});
tour.addStep({
id: 'template-step',
text: () => `
<h3>${document.querySelector('#title').innerText}</h3>
<p>${document.querySelector('#description').innerText}</p>
`,
attachTo: {
element: () => document.querySelector('#container'),
on: 'left'
}
});
document.querySelector('#load-button').addEventListener('click', () => {
tour.next();
});
tour.addStep({
id: 'button-step',
text: async () => {
await waitForElement('#new-section');
return 'Новая секция готова';
},
attachTo: {
element: async () => await waitForElement('#new-section'),
on: 'top'
}
});
Использование ленивой загрузки в Shepherd.js позволяет строить интерактивные туры даже в самых динамичных приложениях, где элементы интерфейса появляются только при взаимодействии или после асинхронных запросов. Это снижает нагрузку на страницу и делает тур максимально адаптивным к состоянию приложения.