현재 나는 지인개발자분들과 사이드 프로젝트를 진행중이다.
레저 정보들을 모아보고, 레저 업체를 예약할 수 있는 플랫폼 사이트로 기획 및 구성! 🏄🏻♀️
이런 저런 기능을 구현하던 중, 스크롤 관련 기능은 이번에 제대로 처음 구현해보기도 하고, 그만큼 헤매고 공부도 많이 됐어서 일단 기능 위주로 먼저 블로그 정리를 해보려고 한다.
압축하고 gif로 변환했더니 영상이 왜 때문에 느려진건지...?
암튼 구현영상이다.
레저정보 섹션과 리뷰 섹션이 나뉘어져 있다.
각 섹션의 시작부분이 nav에 닿는 즉시, 해당 탭의 스타일이 변경되어야 한다.
각 섹션의 상단 부분이 nav에 닿는 스크롤 위치값이 몇인지 파악해야 했다.
window.scrollY
를 console.log로 찍어보면 바로 나온다.
레저정보 섹션은 923 이상이면서 1732 이하일 때만,
리뷰 섹션은 1732 이상일 때만,
탭 스타일이 해당섹션에 맞게 바뀌어야 한다.
useEffect
로 첫 렌더링 시에, document
에 스크롤 이벤트를 직접 추가시켜주어야 한다.useEffect(() => {
document.addEventListener('scroll');
}, []);
scrollY
값에 조건을 걸어주기 위해 상태값을 관리할 useState
를 생성한다.const [scrollPosition, setScrollPosition] = useState(0);
setState
에 계속 변동될 window.scrollY
값을 넣어주는 함수를 useEffect
내부에 만든다.addEventListener
의 2번째 파라미터인, 리스너 콜백함수 자리에 해당 함수를 넣는다. )const [scrollPosition, setScrollPosition] = useState(0);
useEffect(() => {
const scroll = () => {
const { scrollY } = window;
setScrollPosition(scrollY);
};
document.addEventListener('scroll', scroll);
}, []);
addEventListener
의 options
기능 중, 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);
}, []);
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구역으로 나뉘어져 있는데, 각 구역을 클릭할 시 그 구역에 해당하는 섹션의 탑부분으로 자동으로 스크롤을 이동시켜주는 기능이다.
window.scrollTo(x_좌표, y_좌표);
getElementById
로 타겟요소를 잡아온 후, offsetTop
속성을 사용하여 요소의 Y축 위치 값을 가져온다. ( document 기준 )const tabClickHandler = (id: string) => {
window.scrollTo({
top: document.getElementById(id)?.offsetTop,
});
};
behavior
속성의 smooth
도 추가해주었다.const tabClickHandler = (id: string) => {
window.scrollTo({
top: document.getElementById(id)?.offsetTop,
behavior: 'smooth',
});
};
tabClickHandler
함수가 실행되어야 하므로, nav의 각 탭에 onClick
으로 tabClickHandler
함수를 넣어준다. ( 인수로는 타겟요소의 id값이 들어가게 한다. )onClick={() => tabClickHandler('store-info')}
onClick={() => tabClickHandler('review')}
끝!
스크롤 기능.. 간단할 거라고 생각했고, 실제로 완성하고보니 코드도 그리 어려운 것은 없다.
그러나 역시 처음은 어려운 것.. 그리고 document와 window에 대한 지식, addEventListener에 대한 적은 경험 등등 이런 기본기들이 결국 간단한 기능들도 헤매게 한 것 같다.
window와 document의 차이에 대해 공부하고 블로그정리를 해야겠다.