Синхронизация нескольких экземпляров fullPage.js применяется в интерфейсах, где необходимо обеспечить одновременное поведение нескольких независимых областей прокрутки. Типичные сценарии включают:
Каждый экземпляр fullPage.js управляет своим контейнером, поэтому синхронизация требует явного связывания их состояний.
Создание двух независимых экземпляров:
const fp1 = new fullpage('#fullpage1', {
autoScrolling: true,
scrollingSpeed: 700
});
const fp2 = new fullpage('#fullpage2', {
autoScrolling: true,
scrollingSpeed: 700
});
На этом этапе оба экземпляра работают независимо. Для синхронизации необходимо перехватывать события и инициировать действия во втором экземпляре.
fullPage.js предоставляет хуки, которые используются для отслеживания состояния:
afterLoadonLeaveafterSlideLoadonSlideLeaveНаиболее часто используется onLeave, так как он
срабатывает до смены секции.
let isSyncing = false;
const fp1 = new fullpage('#fullpage1', {
onLeave: function(origin, destination, direction) {
if (isSyncing) return;
isSyncing = true;
fullpage_api.moveTo(destination.index + 1);
isSyncing = false;
}
});
Проблема: fullpage_api управляет только текущим
экземпляром. Для работы с несколькими экземплярами необходимо хранить
ссылки:
let isSyncing = false;
const fp1 = new fullpage('#fullpage1', {
onLeave: function(origin, destination) {
if (isSyncing) return;
isSyncing = true;
fp2_api.moveTo(destination.index + 1);
isSyncing = false;
}
});
const fp2 = new fullpage('#fullpage2', {});
const fp2_api = fullpage_api;
При инициализации нескольких экземпляров важно сохранить API каждого:
let fp1_api;
let fp2_api;
fp1_api = new fullpage('#fullpage1', {
afterRender: function() {
fp1_api = this;
}
});
fp2_api = new fullpage('#fullpage2', {
afterRender: function() {
fp2_api = this;
}
});
В более современных версиях API возвращается напрямую:
const fp1_api = new fullpage('#fullpage1', {});
const fp2_api = new fullpage('#fullpage2', {});
Основная проблема синхронизации — бесконечный цикл:
Решение — флаг блокировки:
let isSyncing = false;
function sync(from, to, index) {
if (isSyncing) return;
isSyncing = true;
to.moveTo(index);
isSyncing = false;
}
Использование:
onLeave: function(origin, destination) {
sync(fp1_api, fp2_api, destination.index + 1);
}
Для полной синхронизации требуется обработка событий в обоих экземплярах:
let isSyncing = false;
function sync(targetApi, index) {
if (isSyncing) return;
isSyncing = true;
targetApi.moveTo(index);
isSyncing = false;
}
const fp1_api = new fullpage('#fullpage1', {
onLeave: function(origin, destination) {
sync(fp2_api, destination.index + 1);
}
});
const fp2_api = new fullpage('#fullpage2', {
onLeave: function(origin, destination) {
sync(fp1_api, destination.index + 1);
}
});
fullPage.js поддерживает горизонтальные слайды. Для их синхронизации используются события:
afterSlideLoadonSlideLeaveПример:
let isSyncingSlides = false;
const fp1_api = new fullpage('#fullpage1', {
onSlideLeave: function(section, origin, destination) {
if (isSyncingSlides) return;
isSyncingSlides = true;
fp2_api.moveSlideRight(destination.index);
isSyncingSlides = false;
}
});
Альтернативный вариант с точным управлением:
fp2_api.moveTo(section.index + 1, destination.index);
Иногда количество секций отличается. В этом случае используется сопоставление:
const map = {
1: 1,
2: 3,
3: 5
};
onLeave: function(origin, destination) {
const targetIndex = map[destination.index + 1];
if (targetIndex) {
fp2_api.moveTo(targetIndex);
}
}
Не всегда требуется синхронизировать все секции:
onLeave: function(origin, destination) {
if (destination.index < 3) {
fp2_api.moveTo(destination.index + 1);
}
}
Используется для создания эффектов:
onLeave: function(origin, destination) {
setTimeout(() => {
fp2_api.moveTo(destination.index + 1);
}, 300);
}
Для визуальной согласованности:
const fp1_api = new fullpage('#fullpage1', {
scrollingSpeed: 700
});
const fp2_api = new fullpage('#fullpage2', {
scrollingSpeed: 700
});
Несовпадение скорости приводит к визуальному рассинхрону.
Альтернативный подход — использование событий DOM:
document.addEventListener('fpSync', (e) => {
fp2_api.moveTo(e.detail.index);
});
onLeave: function(origin, destination) {
document.dispatchEvent(new CustomEvent('fpSync', {
detail: { index: destination.index + 1 }
}));
}
Преимущество — слабая связанность компонентов.
Централизованная архитектура:
class SyncController {
constructor() {
this.lock = false;
}
sync(source, targets, index) {
if (this.lock) return;
this.lock = true;
targets.forEach(t => t.moveTo(index));
this.lock = false;
}
}
const controller = new SyncController();
Использование:
onLeave: function(origin, destination) {
controller.sync(fp1_api, [fp2_api], destination.index + 1);
}
const instances = [fp1_api, fp2_api, fp3_api];
function syncAll(index) {
instances.forEach(api => api.moveTo(index));
}
С защитой от циклов:
let lock = false;
function syncAll(index) {
if (lock) return;
lock = true;
instances.forEach(api => api.moveTo(index));
lock = false;
}
При большом количестве экземпляров:
css3: false при
необходимости);let timer;
function debouncedSync(index) {
clearTimeout(timer);
timer = setTimeout(() => {
syncAll(index);
}, 50);
}
1. Зацикливание событий Отсутствие блокировки приводит к бесконечным вызовам.
2. Потеря контекста API Использование
fullpage_api вместо конкретного экземпляра.
3. Несовпадение структуры секций Отсутствие маппинга индексов.
4. Разная скорость анимации Приводит к визуальному рассинхрону.
onLeave: function(origin, destination) {
slider.setActive(destination.index);
}
onLeave: function(origin, destination) {
animateSection(destination.index);
}
Связанная синхронизация Прямые вызовы между экземплярами.
Событийная модель Использование глобальных событий.
Контроллер (рекомендуется) Централизованное управление состоянием.
Если используется scrollBar: true, синхронизация
выполняется через отслеживание scroll:
window.addEventListener('scroll', () => {
const index = Math.round(window.scrollY / window.innerHeight);
fp2_api.moveTo(index + 1);
});
Комбинация вертикальной и горизонтальной:
onLeave: function(origin, destination) {
fp2_api.moveTo(destination.index + 1, 0);
}
Хранение текущей секции:
let currentSection = 1;
onLeave: function(origin, destination) {
currentSection = destination.index + 1;
}
Используется для восстановления состояния или синхронизации при инициализации.
После изменения DOM:
fp1_api.reBuild();
fp2_api.reBuild();
И повторная синхронизация:
fp2_api.moveTo(fp1_api.getActiveSection().index + 1);