코딩/프로젝트

[개인 프로젝트] 풀 페이지 스크롤링 구현하기(+ 네비게이션바)

김기지 2024. 1. 5. 22:03

🖥️ 포트폴리오 프로젝트에서 구현한 풀 페이지 스크롤링에 대한 정리...

 

 

처음엔 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

 

728x90