Здравствуйте! В этой статье мы рассмотрим, как использовать API Intersection Observer. Это API браузера, который позволяет нам определить, когда элемент виден на экране, или (и вот что самое интересное) когда элемент вот-вот станет видимым, и с помощью этого мы можем выполнить какое-то действие.
Существует несколько вариантов использования этого API, например, ленивая загрузка изображений или реализация бесконечной прокрутки, но в этой статье мы будем использовать этот API для взаимодействия с элементами пользовательского интерфейса при прокрутке.
В частности, 🧐 в нашем проекте будет серия статей, и по мере их прокрутки мы будем помечать соответствующий заголовок как «активный».
Я оставляю вам ссылки на демо-версию проекта и на полный репозиторий проекта в GitHub.
Давайте начнем
Первое, что нам нужно сделать, это создать наш проект в Next.js, и мы сделаем это с помощью команды yarn create next-app
.
После запуска нашего проекта мы создадим каталог /components
, в который добавим два компонента: Title
и Article
. Чтобы они выглядели следующим образом:
Title.js
import React from 'react'
import styles from '../styles/Title.module.css'
const Title = ({text, isActive}) => {
return <li className={`${styles.title} ${isActive ? styles.active : ''}`}>{text}</li>
}
export default Title
Article.js
import React from 'react'
import styles from '../styles/Article.module.css'
const Article = ({ id, title, content }) => {
return (
<article className={styles.article} id={id}>
<h2>{title}</h2>
<p className={styles.content}>{content}</p>
</article>
)
}
export default Article
Использование наших компонентов
Когда у нас есть наши компоненты, давайте используем их в файле index.js
, чтобы он выглядел следующим образом:
import React, { useState } from 'react'
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import Title from '../components/Title'
import Article from '../components/Article'
import data from '../data/data.json'
export default function Home() {
const [activeArticle, setActiveArticle] = useState('01');
return (
<main>
<ul>
{data.titles.map(({title, id}) => {
return <Title key={id} text={title} isActive={id === activeArticle} />
})}
</ul>
<div>
{data.articles.map(({id, title, content}) => {
return <Article key={id} title={title} content={content} id={id} />
})}
</div>
</main>
)}
Добавление API наблюдателя перекрестков
Первое, что нам нужно сделать, это создать в index.js
наш observer
, который принимает два параметра:
- Первый — это обратный вызов, который мы хотим выполнить, когда API обнаружит, что прокрутка приблизилась к элементу для наблюдения.
- Второй — это объект, который позволяет нам настроить наш наблюдатель, мы можем указать, как рано или поздно запускать наш обратный вызов, то есть, при каком проценте видимости нашего элемента обратный вызов должен быть выполнен.
После создания наблюдателя нам нужно указать, какие элементы нужно наблюдать. А поскольку в нашем проекте есть несколько элементов для наблюдения, каждый из них получит наблюдателя на реквизит, так что наш index.js
будет выглядеть следующим образом:
// imports..
export default function Home() {
const [activeArticle, setActiveArticle] = useState('01');
const handleIntersect = (entries) => {
if (entries[0].isIntersecting) {
setActiveArticle(entries[0].target.id);
}
};
const createObserver = (target) => {
const options = { threshold: 1.0 };
const observer = new IntersectionObserver(handleIntersect, options);
observer.observe(target);
};
return (
<main>
<ul>
{data.titles.map(({title, id}) => {
return <Title key={id} text={title} isActive={id === activeArticle} />
})}
</ul>
<div>
{data.articles.map(({id, title, content}) => {
return <Article key={id} title={title} content={content} id={id} createObserver={createObserver} />
})}
</div>
</main>
)}
Давайте проанализируем этот код 🤔 .
Функция handleIntersect
является нашим обратным вызовом, это означает, что она будет выполняться каждый раз, когда observer
обнаружит, что наблюдаемый элемент виден.
Этот обратный вызов делает следующее: берет ID наблюдаемого элемента и сохраняет его в состоянии приложения, которое используется для того, чтобы узнать, какой элемент виден, и таким образом пометить соответствующий заголовок как активный.
У нас уже созданы наблюдатель и обратный вызов, теперь нам просто нужно их использовать. А для этого, как мы уже говорили, мы должны послать по свойству наш наблюдатель в каждую статью и выполнить его. Наш Article.js
будет выглядеть следующим образом:
import React, { useEffect, useRef } from 'react'
import styles from '../styles/Article.module.css'
const Article = ({ id, title, content, createObserver }) => {
const el = useRef(null);
useEffect(() => {
createObserver(el.current);
}, []);
return (
<article ref={el} className={styles.article} id={id}>
<h2>{title}</h2>
<p className={styles.content}>{content}</p>
</article>
)
}
export default Article
И вуаля, вот и все 🥳.
Теперь мы создали и настроили наш наблюдатель, и он используется каждым элементом для наблюдения.
Надеюсь, вы сможете применить полученные в этой статье знания в своих проектах.
На этом пока все, до скорой встречи 👋🏻.