진행 중인 사이드 프로젝트에서 맡은 역할 중 한 가지인 랜딩페이지가 어느 정도 완성되어 스크롤이벤트를 적용해보려고 합니다!
스크롤 기능은 웹 페이지에서 긴 콘텐츠나 여러 섹션을 포함하는 페이지에서 사용자 경험을 향상하는 중요한 요소 중 하나입니다.
필수 목표 체크리스트
✔️ wheel 이벤트를 통해 스크롤을 부드럽게 처리하기
✔️ 창 크기(resize)에 따라 동적으로 headerHeight를 계산하여 페이지 스크롤이 원활하게 이루어지도록 만들기
1. 반응형 사이즈에 맞는 헤더높이 계산하기
- 모바일과 웹 사이즈에 따라 헤더의 높이가 다르기 때문에 화면 크기에 따라 헤더의 높이를 계산하여 적용시켜야 했습니다.
const [headerHeight, setHeaderHeight] = useState(0);
// 화면 크기에 맞게 헤더의 높이를 계산하는 함수
const calculateHeaderHeight = () => {
if (window.innerWidth >= 1440) {
setHeaderHeight(80); // 웹 화면에서는 헤더가 80px
} else {
setHeaderHeight(56); // 모바일 화면에서는 헤더가 56px
}
};
※ headerHeight이라는 상태를 만들어주어 헤더의 높이를 저장해 달라지는 화면 크기(window.innerWidth)에 따라 동적으로 계산해 주었습니다.
2. 화면 크기 변경에 따른 headerHeight 동적 업데이트
useEffect(() => {
const handleResize = () => {
calculateHeaderHeight();
};
window.addEventListener("resize", handleResize);
// 초기 페이지 로드시에도 headerHeight를 설정
calculateHeaderHeight();
return () => {
window.removeEventListener("resize", handleResize);
};
}, [setHeaderHeight]);
※ 위에서 계산한 헤더의 높이를 resize 이벤트에 적용하여 화면 크기가 변경될 때마다 headerHeight 값을 업데이트해줍니다.
3. 스크롤 이벤트 처리
wheel 이벤트에서 deltaY 값을 가져와 이를 통해 스크롤의 방향을 감지하고 페이지를 이동시키는 방식으로 진행하였습니다.
이때 페이지가 넘어가는 느낌을 구현하고 싶어 scrollTo 메서드를 사용하고 behavior속성을 이용해 부드러운 스크롤이 진행되도록 하였습니다.
const handleWheel = (e: WheelEvent) => {
e.preventDefault();
const { deltaY } = e;
wheelHandler(deltaY); // deltaY 값으로 스크롤 방향을 처리
};
const wheelHandler = (deltaY: number) => {
const outerDiv = outerDivRef.current;
if (!outerDiv || isScrolling.current) return; // 이미 스크롤 중이라면 무시
isScrolling.current = true; // 스크롤 중임을 표시
const { scrollTop } = outerDiv;
const pageHeight = window.innerHeight - headerHeight; // 페이지 높이에서 헤더를 제외한 부분
const totalPages = 5; // 총 페이지 수
const currentPage = Math.round(scrollTop / pageHeight); // 현재 페이지 번호 계산
if (deltaY > 0) {
// 스크롤을 내릴 때
if (currentPage < totalPages - 1) {
outerDiv.scrollTo({
top: (currentPage + 1) * pageHeight,
left: 0,
behavior: "smooth",
});
}
} else {
// 스크롤을 올릴 때
if (currentPage > 0) {
outerDiv.scrollTo({
top: (currentPage - 1) * pageHeight,
left: 0,
behavior: "smooth",
});
}
}
// 1.2초 후 스크롤 가능 상태로 되돌리기
setTimeout(() => {
isScrolling.current = false;
}, 1200);
};
4. 이벤트 리스너 등록하기
이제 만들어준 함수를 이벤트 리스너에 적용시켜 주면 끝입니다!
const outerDivRefCurrent = outerDivRef.current;
if (outerDivRefCurrent) {
outerDivRefCurrent.addEventListener("wheel", handleWheel, { passive: false });
}
return () => {
if (outerDivRefCurrent) {
outerDivRefCurrent.removeEventListener("wheel", handleWheel);
}
};
※ 이벤트를 등록할 때 옵션으로 { passive: false }를 넣어주면 이벤트 핸들러가 e.preventDefault()를 사용할 수 있게 해 주기 때문에 기본 스크롤 동작을 막고 커스텀한 페이지 스크롤을 사용할 수 있게 해 줍니다.
완성!!
어려웠지만 내가 해냄
'TIL' 카테고리의 다른 글
Oeasy 프로젝트 유저피드백 반영하기 (0) | 2024.12.19 |
---|---|
CSR과 SSR은 무엇일까? (1) | 2024.08.29 |
Next.js를 사용하는 이유와 App Router와 Pages Router (0) | 2024.08.27 |
로그인 회원가입의 기본 인증 / 인가 이해하기 (0) | 2024.07.19 |
redux 사용법 (0) | 2024.06.26 |