Недавно мне пришлось сделать Scrollspy для моего личного веб-портфолио. Я хотел использовать Intersection Observer, так как сейчас он широко поддерживается. К сожалению, это не так просто, и в Интернете не так много говорится о том, как заставить его работать. Итак, я решил написать небольшую статью, чтобы помочь другим, ищущим то же самое.
Scrollspy - это механизм навигации, используемый Bootstrap. Согласно документам,
Прокрутка
Автоматически обновляйте компоненты навигации или группы списков в зависимости от положения прокрутки, чтобы указать, какая ссылка в данный момент активна в области просмотра.
По сути, это часть JavaScript, которая позволяет вашим заголовкам и спискам знать, какой элемент в данный момент находится на экране. Обычно это используется для выделения активного раздела на панели навигации.
Наблюдатель за перекрестком
Раньше эффект достигался с помощью прослушивателя событий прокрутки, который проверял все разделы один за другим при каждой прокрутке, а затем обновлял раздел, который в данный момент находится в окне просмотра, чтобы он стал активным. К счастью, у нас есть новый IntersectionObserver
API, который упрощает задачу и делает ее более эффективной.
IntersectionObserver
используется для мониторинга определенной части области просмотра, чтобы проверить, когда указанные узлы DOM пересекаются с этой областью. Каждый раз, когда узел входит в регион или покидает его, выполняется обратный вызов.
Если вы не знаете об IntersectionObserver
API, прочтите эту отличную статью. Ключевое преимущество наблюдателя пересечения заключается в том, что в отличие от прослушивателя событий прокрутки он является асинхронным.
Параметры и опции
IntersectionObserver
API принимает следующие параметры:
- Корень пересечения: область, которая должна отслеживаться на предмет пересечения с указанными узлами. По умолчанию используется область просмотра, но также может быть установлен узел DOM.
- Поле корня: по умолчанию отслеживается весь корень. Но мы можем указать поля вокруг корня, чтобы контролировать большую (или меньшую, если поля отрицательные) область, чем корень.
- Порог: значение от 0 до 1, которое указывает, какая часть целевого элемента (элементов) должна находиться в корне пересечения для запуска функции обратного вызова. 0 означает, как только один пиксель входит в область или как только весь узел покидает область. 1 означает, что весь узел должен быть в регионе. Несколько значений могут быть предоставлены в виде массива.
- Обратный вызов: функция, вызываемая всякий раз, когда происходит пересечение.
Первый шаг - создать наблюдателя, используя указанные выше параметры. Затем целевые элементы регистрируются наблюдателем пересечения. Если какой-либо из элементов пересекается с указанной областью в пределах пороговых значений, вызывается обратный вызов. Согласно MDN, синтаксис обратного вызова:
let callback = (entries, observer) => {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
entries
параметр содержит запись для всех наблюдаемых узлов. Чтобы узнать, какая запись пересекается с корнем, используйте свойство entry.isIntersecting
.
Техника
Допустим, у нас есть страница с несколькими разделами, и нам нужно найти тот, который в настоящее время находится в центре внимания. Здесь мы делаем следующее:
- Оставьте
threshold
равным0
(значение по умолчанию). Это означает, что всякий раз, когда первый пиксель любого раздела входит в область просмотра или последний пиксель любого раздела покидает корень, будет выполняться обратный вызов. - По умолчанию корень пересечения - это вся область просмотра. Мы хотим, чтобы пересечение наблюдалось на горизонтальной линии. Мы можем сделать это, добавив поля к корню и уменьшив наблюдаемую область до горизонтальной линии. Чтобы установить его ровно посередине экрана, установите
rootMargin
на-50% 0px
. - Получите список всех разделов на странице и подключите их к наблюдателю пересечения.
- Каждый раз, когда происходит пересечение, выясняйте, какой элемент вызвал пересечение. Для этого используйте свойство
entry.isIntersecting
.
Код довольно прост:
window.onload = () => { const sections = document.getElementsByTagName("section"); const label = document.getElementById("section-name"); const observer = new IntersectionObserver((entries) => { for(const entry of entries) if(entry.isIntersecting) label.innerHTML = entry.target.innerText; },{ rootMargin: "-50% 0px" }); for (let i = 0; i < sections.length; i++) observer.observe(sections[i]); };
Вы можете увидеть это в действии здесь: http://intersection-scrollspy.surge.sh/