[개인 프로젝트] 풀 페이지 스크롤링 구현하기(+ 네비게이션바)
🖥️ 포트폴리오 프로젝트에서 구현한 풀 페이지 스크롤링에 대한 정리...
처음엔 react-scroll 라이브러리를 사용해 네이게이션 메뉴를 구현했다.
스크롤 이동에 따라 컴포넌트를 인지해 표시하는 부분까지는 구현이 되었지만 스크롤 방향에 따른 풀 페이지 스크롤링 동작은 잘 되지 않아 라이브러리를 사용하지 않고 직접 구현했다.
참고한 블로그는 하단에 표기하였다.
1. 화면을 구성하는 컴포넌트 설정하기
각 컴포넌트는 전체 화면을 가득 채워야 하기 때문에 높이를 100vh로 설정한다.
export const Page = styled.div`
height: 100vh;
`;
컴포넌트를 담고 있는 App 컴포넌트에서는 각 컴포넌트가 스크롤 이동으로 화면에 나타나도록 해야하므로 overflow-y를 scroll로 설정한다.
const AppComponent = styled.div`
height: 100vh;
overflow-y: scroll;
`;
스크롤 동작을 감지하기 위해 useRef를 사용하여 App 컴포넌트에 접근한다.
const App = () => {
const pageRef = useRef<HTMLDivElement | null>(null);
return (
<AppComponent ref={pageRef}>
<NavBar/>
<div>
<Title />
</div>
<div>
<About />
</div>
<div>
<Project />
</div>
<div>
<Contact />
</div>
</AppComponent>
);
};
2. 스크롤 동작 함수 구현하기
❗️ PC 환경에서는 마우스 스크롤 동작으로, 모바일 환경에서는 터치 스크롤 동작으로 스크롤링을 동작한다.
포트폴리오 스크롤 동작은 pc와 모바일 두 환경에서 동일하게 동작해야 한다.
따라서 wheel 이벤트와 touch 이벤트 핸들러를 사용해 함수를 구현한다.
- wheel 이벤트
- 세로 스크롤 양을 나타내는 deltaY 속성을 사용해 이벤트 방향을 파악
- touch 이벤트
- deltaY와 같은 속성이 없으므로 표면과의 모든 접촉 지점을 나타내는 touches의 Y좌표를 가져와 방향을 파악
이벤트 핸들러는 실존하는 DOM에 달아줘야 하므로 컴포넌트가 마운트 된 이후에 달아줄 수 있도록 useEffect 내부에서 구현한다.
추가로 useEffect의 리턴문에서 컴포넌트 언마운트 시 handler 함수를 지우면 메모리를 절약할 수 있다.
useEffect(() => {
// 회면 세로 길이
const pageHeight = window.innerHeight;
let startY: number;
// 모바일에서 터치 스크롤 시
// 터치가 발생된 지점의 Y 좌표를 저장
const touchStartHandler = (e: TouchEvent) => {
startY = e.touches[0].clientY;
};
const scrollHandler = (e: WheelEvent | TouchEvent) => {
e.preventDefault();
// 'deltaY'가 있는지 확인하여 터치 이벤트와 휠 이벤트를 구분
// 터치 이벤트 시 현재 터치 지점과 시작 터치 지점간의 거리 차를 구함
const deltaY = 'deltaY' in e ? e.deltaY : startY - e.touches[0].clientY;
}
pageRef.current?.addEventListener('wheel', scrollHandler);
pageRef.current?.addEventListener('touchstart', touchStartHandler);
pageRef.current?.addEventListener('touchmove', scrollHandler);
return () => {
pageRef.current?.removeEventListener('wheel', scrollHandler);
pageRef.current?.removeEventListener('touchstart', touchStartHandler);
pageRef.current?.removeEventListener('touchmove', scrollHandler);
};
}, []);
touch 이벤트에서는 스크롤 양을 알 수 없기 때문에 초기 터치 지점에서 나중 지점을 뺀 값을 구해
- 뺀 값이 양수 -> 아래 스크롤
- 뺀 값이 음수 -> 위 스크롤
으로 파악한다.
↓ 터치 시 스크롤 방향 파악하는 방법
[Android] ListView에서 스크롤 방향 체크하기
ListView에서 스크롤 방향 체크하기 스크롤뷰, 혹은 리스트뷰에서 터치이벤트를 이용해서 스크롤이 위, 아래중 어디로 움직이는지 확인하는 방법을 포스팅해 보겠습니다. boolean firstDragFlag = true; bo
crespo.tistory.com
pageRef의 상단 위치의 값을 가져와 스크롤 동작 시 방향에 따라 높이가 이동하도록 동작을 구현한다.
아래스크롤 시
-> 현재 pageRef의 상단 위치가 0에서 페이지 높이 사이(1 페이지)라면
-> pageRef의 top 위치를 페이지 높이만큼 이동(2 페이지)
위와 같은 로직으로 스크롤 방향에 따라 pageRef의 상단 위치를 설정한다.
const scrollHandler = (e: WheelEvent | TouchEvent) => {
e.preventDefault();
const deltaY = 'deltaY' in e ? e.deltaY : startY - e.touches[0].clientY;
const { current: pageRefCurrent } = pageRef;
if (pageRefCurrent) {
const { scrollTop } = pageRefCurrent;
if (deltaY > 0) {
// 아래로 스크롤
if (scrollTop >= 0 && scrollTop < pageHeight) {
pageRef.current?.scrollTo({
top: pageHeight,
left: 0,
behavior: 'smooth',
});
} else if (scrollTop >= pageHeight && scrollTop < pageHeight * 2) {
pageRef.current?.scrollTo({
top: pageHeight * 2,
left: 0,
behavior: 'smooth',
});
} else if (
scrollTop >= pageHeight * 2 &&
scrollTop < pageHeight * 3
) {
pageRef.current?.scrollTo({
top: pageHeight * 3,
left: 0,
behavior: 'smooth',
});
} else if (
scrollTop >= pageHeight * 3 &&
scrollTop < pageHeight * 4
) {
pageRef.current?.scrollTo({
top: pageHeight * 4,
left: 0,
behavior: 'smooth',
});
}
} else if (deltaY < 0) {
// 위로 스크롤
if (scrollTop >= 0 && scrollTop < pageHeight) {
pageRef.current?.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
} else if (scrollTop >= pageHeight && scrollTop < pageHeight * 2) {
pageRef.current?.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
} else if (
scrollTop >= pageHeight * 2 &&
scrollTop < pageHeight * 3
) {
pageRef.current?.scrollTo({
top: pageHeight,
left: 0,
behavior: 'smooth',
});
} else if (
scrollTop >= pageHeight * 3 &&
scrollTop < pageHeight * 4
) {
pageRef.current?.scrollTo({
top: pageHeight * 2,
left: 0,
behavior: 'smooth',
});
}
}
}
};
🔗 참고 링크
[react] 리액트 전체화면 넘기기 스크롤링(full page scroll)
리액트 전체화면 스크롤링 마우스 휠 움직임에 반응하여 전체화면을 스크롤링하는 코드를 구현해 보겠습니다. 1. outer div와 inner div(3개)를 생성해 줍니다. inner div는 각각 위 결과물의 1,2,3페이지
codingbroker.tistory.com