브라우저에서 제공하는 API 중 하나로, 요소가 뷰포트에 나타날 때를 관찰하는 API
따라서 나타나는 그 시점에 특정 코드를 수행하게 할 수 있다.
무한 스크롤은 사용자가 페이지 하단에 도달했을 때마다 요소들을 추가로 로드해서 마치 무한히 스크롤 할 수 있다는 사용자 경험을 주는 기능이다. 이것을 Intersection Observer API
로 구현할 수 있다.
먼저 무한 스크롤을 보기 전에 이해를 돕기 위한 첫 번째 예시로 스크롤 가능한 페이지 하단에 원이 있다고 할 때
Intersection Observer API
를 사용하면 사용자에게 원이 표시되는 시점을 감지해서 특정 코드를 수행할 수 있다.
<body>
<div id="circle"></div>
</body>
// 1. 감지할 요소를 취득하고
const $circle = document.getElementById('circle');
// 2. IntersectionObserver 생성자 함수 호출
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
console.log(entry.target, 'visible !!');
}
});
},
{
// 옵션 객체
// root: null,
// rootMargin: '0px',
// threshold: 1.0
}
);
// 3. observer에게 요소가 감지되면 콜백함수를 실행하라고 지시한다.
observer.observe($circle);
다음과 같이 콘솔에 결과가 잘 나오는 것을 확인할 수 있다.
위 2번 코드를 자세히 살펴보면...
IntersectionObserver
생성자 함수를 호출하는데 이때 요소를 감지했을 때 실행할 콜백 함수를 필수로 넣어주어야 한다. 두 번째 인수로 옵션 객체를 넣어주는데 이는 선택사항이다.
참고로 옵션 객체에는 다음과 같은 속성들이 있다.
{
root: null, // 뷰포트를 기준으로 설정
rootMargin: '0px', // 루트 영역에 대한 여백 설정
threshold: 0.5 // 요소의 50%가 뷰포트 안에 들어올 때 콜백함수 실행
};
isIntersecting
속성으로 배열의 각 요소들이 화면에 나타나는지 확인해서 특정 코드를 수행하게 한다.
이제 본격적으로 무한 스크롤을 구현해 볼건데 원리는 간단하다.
Intersection Observer API
로 그 대상을 관찰한 뒤 그 요소가 화면에 보이게 되면 서버에 다음 페이지에 대한 데이터를 요청하여 렌더링하는 것이다.이때 주의할 점은 한번 감지가 된 요소는 unobserve
메서드로 관찰을 취소하여 함수를 실행시키지 않는 것이다.
<div id="postsContainer"></div>
(function () {
'use strict';
const $postsContainer = document.getElementById('postsContainer');
let currentPage = 1;
const limit = 10;
const setScrollObserver = ($scrollObserverElement) => {
const callback = async (entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
const postList = await getPosts(++currentPage);
if (postList.length > 0) {
renderPostList(postList);
}
// 요소가 관찰된 이후 요소 제거 및 관찰을 취소하지 않으면
// 그 요소가 isIntersecting될 때마다 콜백함수가 실행되는 문제가 발생한다.
observer.unobserve(entry.target);
entry.target.remove();
}
}
};
// 3. 인스턴스를 생성하고 전달한 요소가 관찰되면 콜백함수를 실행시키라고 지시한다.
const observer = new IntersectionObserver(callback);
observer.observe($scrollObserverElement);
};
const createObserverElement = () => {
// div 요소 생성 후 반환
};
const renderPostList = (postList) => {
// forEach
// innerHTML
// 2. 추가된 요소 마지막에 무한 스크롤 현상을 일으킬 관찰될 요소를 추가한다.
const $observerElement = createObserverElement();
$postsContainer.appendChild($observerElement);
setScrollObserver($observerElement);
};
const getPosts = async (currentPage) => {
// fetch
};
// 1. init 함수가 실행되면 1번 페이지의 아이템을 요청하고 렌더링한다.
const init = async () => {
const postList = await getPosts(currentPage);
renderPostList(postList);
};
init();
})();