Intro.js — это библиотека для создания пошаговых интерактивных руководств по интерфейсу веб-приложения. Одной из важных особенностей при работе с большими страницами или динамическим контентом является ленивая загрузка шагов. Она позволяет загружать и инициализировать шаги только тогда, когда они действительно нужны, что снижает нагрузку на DOM и улучшает производительность.
Intro.js поддерживает динамическое определение шагов
через функцию onbeforechange или при помощи массивов
объектов, передаваемых в метод setOptions. Пример структуры
шага:
{
element: '#feature-button',
intro: 'Это основной функциональный элемент.',
position: 'right'
}
Для ленивой загрузки можно создать функцию, которая добавляет шаги по мере навигации:
let steps = [
{ element: '#step1', intro: 'Первый шаг.' }
];
const intro = introJs();
intro.setOptions({ steps: steps });
intro.onbeforechange(function(targetElement) {
if (targetElement.id === 'step1') {
steps.push({
element: '#step2',
intro: 'Второй шаг загружен динамически.',
position: 'bottom'
});
intro.setOptions({ steps: steps });
}
});
intro.start();
Здесь второй шаг создается только при переходе к первому. Это предотвращает ненужную инициализацию элементов на странице, которые еще не отображены.
Для сложных интерфейсов часто используется динамическое создание DOM-элементов перед добавлением шага. Например:
intro.onbeforechange(function(targetElement) {
if (targetElement.id === 'container' && !document.querySelector('#dynamic-button')) {
const button = document.createElement('button');
button.id = 'dynamic-button';
button.textContent = 'Новый функционал';
document.querySelector('#container').appendChild(button);
steps.push({
element: '#dynamic-button',
intro: 'Этот элемент появился только сейчас!',
position: 'top'
});
intro.setOptions({ steps: steps });
}
});
Это особенно важно при работе с SPA (Single Page Application), где контент часто подгружается через AJAX.
onafterchange для оптимизацииСобытие onafterchange позволяет инициализировать
или активировать контент сразу после отображения шага. Это
удобно для ленивой загрузки сложных виджетов:
intro.onafterchange(function(targetElement) {
if (targetElement.id === 'chart-container' && !window.chartInitialized) {
initChart('#chart-container'); // функция инициализации графика
window.chartInitialized = true;
}
});
Такой подход предотвращает нагрузку на страницу при первоначальной загрузке и ускоряет старт интро.
В некоторых случаях контент шага полностью загружается с сервера. Для этого можно использовать асинхронные вызовы:
intro.onbeforechange(async function(targetElement) {
if (targetElement.id === 'remote-step' && !targetElement.dataset.loaded) {
const response = await fetch('/api/step-content');
const data = await response.text();
targetElement.innerHTML = data;
targetElement.dataset.loaded = 'true';
}
});
Такой подход позволяет поддерживать интро даже при большом объеме данных, без блокировки основного потока исполнения.
При ленивой загрузке стоит учитывать несколько ключевых аспектов:
onbeforechange и
onafterchange для динамического создания
контента.let steps = [
{ element: '#step1', intro: 'Начало интро.' }
];
const intro = introJs();
intro.setOptions({ steps: steps });
intro.onbeforechange(async function(targetElement) {
if (targetElement.id === 'step1') {
const dynamicContainer = document.createElement('div');
dynamicContainer.id = 'step2';
document.body.appendChild(dynamicContainer);
const response = await fetch('/api/step2-content');
dynamicContainer.innerHTML = await response.text();
steps.push({
element: '#step2',
intro: 'Контент загружен динамически!',
position: 'left'
});
intro.setOptions({ steps: steps });
}
});
intro.start();
В этом примере шаги создаются по мере необходимости, а тяжелый контент загружается асинхронно, снижая нагрузку на страницу и ускоряя старт интро.