브라우저 Scroll Event 사용하기
요즈음 웹 사이트들은 스크롤을 통한 이벤트 발생을 많이 일으키는 것 같다.
그리고 그 기본은 스크롤의 변화를 탐지하여 현재 사용자가 보고있는 페이지를 확인하는 것이다.
모바일 웹에서 흔히 사용되는 무한 스크롤 역시, 컴포넌트의 위치와 현재 사용자가 보고 있는 스크롤 위치를 파악하여 마지막에 도달하였을 때 자동으로 서버로 요청을 보내어 새로운 데이터를 가져오는 것 이다.
현재까지 사용자가 스크롤해온 값은 window.pageYOffset이나 window.scrollY로 확인할 수 있다.
window.pageYOffset은 deprecated 되었다고 알려졌지만, IE 환경을 고려한다면 이를 사용해야 한다.
window.scrollY는 window.pageYOffset와 같은 값을 가지므로, window.pageYOffset를 대체할 수 있다.
🍉 무한스크롤 구현을 위해서 다음과 같은 코드로 페이지에 끝에 도달했는지 확인할 수 있다.
const now = window.scrollY + document.documentElement.clientHeight;
const end = document.documentElement.scrollHeight;
console.log(now >= end ? '페이지의 끝에 도달하였습니다.' : "스크롤 가능한 상태입니다.");
위의 코드를 살펴보자면, window.scrollY는 현재 사용자가 얼마나 스크롤을 했는지 number 값으로 표현해주는 변수이다.
clientHeight는 CSS상의 높이 + CSS상의 내부 여백 - 수평 스크롤바의 높이로 계산되는데, 간단히 말하자면 콘텐츠가 차지하는 영역의 높이를 의미한다.
즉, 사용자가 지금껏 스크롤해온 값에 clientHeight는 뷰포트(사용자가 보고있는 화면)의 높이를 더한 것이 전체 HTML 문서의 높이와 같거나 크다면 마지막에 도달한 것으로 볼 수 있는 것이다.
🍖 스크롤의 값에 따라서 오차가 발생할 수 있기에, 위의 코드에서 now가 end 값을 초과하는 경우를 고려하는 것이 좋다.
https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight
Element.clientHeight - Web APIs | MDN
The Element.clientHeight read-only property is zero for elements with no CSS or inline layout boxes; otherwise, it's the inner height of an element in pixels. It includes padding but excludes borders, margins, and horizontal scrollbars (if present).
developer.mozilla.org
위의 코드는 스크롤을 끝까지 했을 때를 참조하지만, 대부분의 경우에는 특정 요소가 뷰포트에 노출되는지 확인하고 싶은 경우가 많을 것이다.
이 경우, 해당 요소의 높이를 구하여 현재 스크롤된 위치와 비교함으로써 현재 사용자가 해당 요소를 보고 있는지 확인할 수 있다.
<div>
<p class="div-1 ele-phrase">test phrase</p>
</div>
body {
margin: 0;
padding: 0;
}
.div-1.ele-phrase {
color: blue;
margin-top: 100px;
}
위와 같이 기본적으로 세팅된 요소가 있다고 했을 때, p 태그를 가져와 이 HTML 문서에서 이 태그의 절대 위치를 찾는 코드를 작성해보자.
const elem = document.querySelector('.div-1.ele-phrase');
const elemTop = elem.getBoundingClientRect().top;
console.log(elemTop);
위와 같이 코드를 작성하면, 이 요소의 y좌표를 알 수 있다. 위에서는 여백을 제거하고 다시 100px의 여백을 주었으므로, 100의 위치에 존재한다.
하지만, 조금 더 찾아보니 사실 이 위치는 뷰포트의 시작 위치를 기반으로 한 상대적인 y 좌표이고, 문서 전체를 기준으로한 위치를 구하고자 한다면 다음과 같이 작성해야 한다.
const elem = document.querySelector('.div-1.ele-phrase');
const elemYOffset = window.scrollY + elem.getBoundingClientRect().top;
console.log(elemYOffset);
위와 같이 현재까지 스크롤된 y값을 더해주면 이제 진짜 이 요소의 절대값 y 위치를 알 수 있는 것이다.
리액트에서는 react-intersection-observer 라이브러리의 훅을 사용하여 간단하게 해당 컴포넌트가 현재 사용자의 화면에 노출되고 있는지 확인할 수 있다.
import { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';
function App() {
const { ref, inView } = useInView({
threshold: 0,
});
useEffect(() => {
if(inView) {
console.log("Now this element Showing!!");
}
}, [inView]);
return (
<div ref={ref}>
<p>Hi!!!</p>
</div>
);
}
export default App;
ref로 확인할 요소를 특정하고, inView 변수의 값을 확인하여 true라면 사용자의 화면에 그 요소가 보여지는 중임을 알 수 있다.
https://www.npmjs.com/package/react-intersection-observer
react-intersection-observer
Monitor if a component is inside the viewport, using IntersectionObserver API. Latest version: 9.4.3, last published: 18 days ago. Start using react-intersection-observer in your project by running `npm i react-intersection-observer`. There are 806 other p
www.npmjs.com