Waypoints — это библиотека для отслеживания позиции элементов на странице и срабатывания событий при пересечении определённой точки прокрутки. Стандартные адаптеры (jQuery, Zepto, Vanilla) позволяют интегрировать Waypoints с разными фреймворками, но создание собственного адаптера расширяет возможности библиотеки и делает её совместимой с любыми DOM-манипуляторами.
Адаптер в Waypoints — это объект, который реализует унифицированный интерфейс для работы с элементами DOM и обеспечивает следующие ключевые методы:
Adapter(element) – конструктор,
создающий обёртку над DOM-элементом.offset() – возвращает текущую позицию
элемента относительно документа.scrollParent() – определяет ближайший
прокручиваемый контейнер.find(selector) – поиск дочерних
элементов внутри текущего элемента.children() – возвращает все дочерние
элементы.parent() – возвращает родительский
элемент.addClass(className) /
removeClass(className) – управление
CSS-классами.trigger(event, args) – генерация
пользовательских событий.on(event, handler) /
off(event, handler) – привязка и отвязка
событий.Каждый метод адаптера должен корректно работать с нативными DOM-элементами или библиотекой, для которой создаётся адаптер.
Конструктор адаптера получает DOM-элемент и сохраняет его внутри объекта:
function MyAdapter(element) {
this.element = element;
}
MyAdapter.prototype.offset = function() {
const rect = this.element.getBoundingClientRect();
return {
top: rect.top + window.pageYOffset,
left: rect.left + window.pageXOffset
};
};
Пояснение: метод offset() вычисляет
позицию элемента относительно документа, используя
getBoundingClientRect() и текущую прокрутку страницы.
Метод scrollParent() позволяет Waypoints корректно
определять, относительно чего измерять позиции:
MyAdapter.prototype.scrollParent = function() {
let parent = this.element.parentNode;
while (parent) {
const overflowY = window.getComputedStyle(parent).overflowY;
if (overflowY === 'auto' || overflowY === 'scroll') {
return parent;
}
parent = parent.parentNode;
}
return window;
};
Ключевой момент: если ни один родитель не
прокручивается, контейнером считается window.
Методы find, children и parent
обеспечивают навигацию по DOM:
MyAdapter.prototype.find = function(selector) {
return Array.from(this.element.querySelectorAll(selector)).map(el => new MyAdapter(el));
};
MyAdapter.prototype.children = function() {
return Array.from(this.element.children).map(el => new MyAdapter(el));
};
MyAdapter.prototype.parent = function() {
return new MyAdapter(this.element.parentNode);
};
Особенность: методы должны возвращать новые экземпляры адаптера, чтобы сохранить цепочку вызовов Waypoints.
Методы для работы с CSS и событиями реализуются следующим образом:
MyAdapter.prototype.addClass = function(className) {
this.element.classList.add(className);
};
MyAdapter.prototype.removeClass = function(className) {
this.element.classList.remove(className);
};
MyAdapter.prototype.on = function(event, handler) {
this.element.addEventListener(event, handler);
};
MyAdapter.prototype.off = function(event, handler) {
this.element.removeEventListener(event, handler);
};
MyAdapter.prototype.trigger = function(event, args) {
const customEvent = new CustomEvent(event, { detail: args });
this.element.dispatchEvent(customEvent);
};
Важный момент: использование
CustomEvent обеспечивает передачу дополнительных данных в
обработчики событий Waypoints.
После реализации всех методов адаптер нужно зарегистрировать, чтобы Waypoints мог его использовать:
window.Waypoint.adapters.myAdapter = {
Adapter: MyAdapter,
// метод для проверки совместимости, можно возвращать true
isAdapter: function(el) {
return el instanceof HTMLElement;
}
};
Теперь при создании нового Waypoint можно указать
adapter: 'myAdapter':
new Waypoint({
element: document.getElementById('section1'),
handler: function(direction) {
console.log('Waypoint сработал:', direction);
},
adapter: 'myAdapter',
offset: '50%'
});
offset() вычислял актуальное положение элемента при каждом
вызове.Создание собственного адаптера открывает возможность интегрировать Waypoints с любыми фреймворками или нативным DOM, расширяя функциональность и повышая гибкость управления событиями прокрутки и элементами на странице.