사이드 프로젝트 | 스크롤 관련 2가지 기능 구현

앙두·2023년 9월 26일
0

JavaScript

목록 보기
21/21

현재 나는 지인개발자분들과 사이드 프로젝트를 진행중이다.
레저 정보들을 모아보고, 레저 업체를 예약할 수 있는 플랫폼 사이트로 기획 및 구성! 🏄🏻‍♀️

이런 저런 기능을 구현하던 중, 스크롤 관련 기능은 이번에 제대로 처음 구현해보기도 하고, 그만큼 헤매고 공부도 많이 됐어서 일단 기능 위주로 먼저 블로그 정리를 해보려고 한다.




구현 영상

압축하고 gif로 변환했더니 영상이 왜 때문에 느려진건지...?
암튼 구현영상이다.



1. 스크롤 위치에 따라 알맞은 탭 구역에 불켜지는 기능

레저정보 섹션과 리뷰 섹션이 나뉘어져 있다.
각 섹션의 시작부분이 nav에 닿는 즉시, 해당 탭의 스타일이 변경되어야 한다.

각 섹션의 상단 부분이 nav에 닿는 스크롤 위치값이 몇인지 파악해야 했다.
window.scrollY를 console.log로 찍어보면 바로 나온다.

레저정보 섹션은 923 이상이면서 1732 이하일 때만,
리뷰 섹션은 1732 이상일 때만,
탭 스타일이 해당섹션에 맞게 바뀌어야 한다.

  1. 먼저 useEffect로 첫 렌더링 시에, document에 스크롤 이벤트를 직접 추가시켜주어야 한다.
    (나는 이때 document가 아닌, window에 걸어주어서 계속 제대로 작동하지 않았었다ㅠㅠ.. window가 아닌 document에 이벤트를 걸어주어야 한다!!)
useEffect(() => {
  document.addEventListener('scroll');
}, []);

  1. 그리고 미리 파악해놓은 각 섹션의 scrollY값에 조건을 걸어주기 위해 상태값을 관리할 useState를 생성한다.
const [scrollPosition, setScrollPosition] = useState(0);

  1. 위아래로 스크롤 이벤트가 발생할 시에, 실시간으로 스크롤 위치값이 업데이트 되어야 하기 때문에, setState에 계속 변동될 window.scrollY값을 넣어주는 함수를 useEffect내부에 만든다.
    ( addEventListener의 2번째 파라미터인, 리스너 콜백함수 자리에 해당 함수를 넣는다. )
const [scrollPosition, setScrollPosition] = useState(0);


useEffect(() => {
    const scroll = () => {
      const { scrollY } = window;
      setScrollPosition(scrollY);
    };

    document.addEventListener('scroll', scroll);
  }, []);

  1. 그리고 addEventListeneroptions 기능 중, passive라는 기능이 있다. touch나 wheel 등 스크롤 퍼포먼스를 대폭 향상시킬 수 있는 '웹 표준 기능'이다. 기본값은 false이기에, 나는 스크롤 이벤트에 알맞게 true로 설정해주었다.
    passive에 대한 추가적인 지식을 얻고 싶다면, 매우 잘 정리된 이 블로그를 참고하면 좋을 듯!
const [scrollPosition, setScrollPosition] = useState(0);


useEffect(() => {
    const options = { passive: true };
    const scroll = () => {
      const { scrollY } = window;
      setScrollPosition(scrollY);
    };

    document.addEventListener('scroll', scroll, options);
  }, []);

  1. 마지막으로 해당 페이지 unmount 시, 이벤트를 깔끔하게 removeEventListener 해주는 것도 잊지말자.
const [scrollPosition, setScrollPosition] = useState(0);


useEffect(() => {
    const options = { passive: true };
    const scroll = () => {
      const { scrollY } = window;
      setScrollPosition(scrollY);
    };

    document.addEventListener('scroll', scroll, options);
    return () => document.removeEventListener('scroll', scroll);
  }, []);

scrollPosition state를 사용하여, 정확한 scrollY 위치값에 따라 스타일이 변화될 수 있도록 구현했다.

scrollPosition && scrollPosition > 923 && scrollPosition < 1732 ? 'leisureTab ' : ''

개선되어야 할 점

현재는, 각 섹션의 scrollY의 위치값을 하드코딩으로 해주었는데,
사실 디바이스의 세로 사이즈가 다 다르기 때문에, scrollY의 위치값도 조금씩 다 다를 것이다.
그렇기 때문에, 세로 사이즈에 비례하여 scrollY의 위치값도 자동으로 계산되어 어느 디바이스에서나 해당 기능이 자연스럽게 잘 작동될 수 있도록 개선이 필요하다.


2. 탭을 클릭하면, 해당 섹션으로 스크롤이 자동으로 이동되는 기능

탭이 2구역으로 나뉘어져 있는데, 각 구역을 클릭할 시 그 구역에 해당하는 섹션의 탑부분으로 자동으로 스크롤을 이동시켜주는 기능이다.

  1. 문서의 지정된 위치로 이동해주는 기능인 window.scrollTo 활용했다.
window.scrollTo(x_좌표, y_좌표);

  1. 타겟요소의 상단으로 이동해야 하기 때문에, getElementById로 타겟요소를 잡아온 후, offsetTop 속성을 사용하여 요소의 Y축 위치 값을 가져온다. ( document 기준 )
const tabClickHandler = (id: string) => {
  window.scrollTo({
    top: document.getElementById(id)?.offsetTop,
  });
};

  1. 이동 시, 부드럽게 이동시키기 위해 behavior 속성의 smooth 도 추가해주었다.
const tabClickHandler = (id: string) => {
  window.scrollTo({
    top: document.getElementById(id)?.offsetTop,
    behavior: 'smooth',
  });
};

  1. 그리고 구역을 클릭 시에, tabClickHandler 함수가 실행되어야 하므로, nav의 각 탭에 onClick으로 tabClickHandler 함수를 넣어준다. ( 인수로는 타겟요소의 id값이 들어가게 한다. )
onClick={() => tabClickHandler('store-info')}
onClick={() => tabClickHandler('review')}

끝!


느낀점

스크롤 기능.. 간단할 거라고 생각했고, 실제로 완성하고보니 코드도 그리 어려운 것은 없다.
그러나 역시 처음은 어려운 것.. 그리고 document와 window에 대한 지식, addEventListener에 대한 적은 경험 등등 이런 기본기들이 결국 간단한 기능들도 헤매게 한 것 같다.

window와 document의 차이에 대해 공부하고 블로그정리를 해야겠다.

profile
쓸모있는 기술자

0개의 댓글