들어가며
카카오뱅크 인재영입 페이지를 보면,
위와 같이 목록을 스크롤 함에 따라 강조되는 키워드가 다름을 알 수 있습니다. 스크롤에 따른 인터랙션은 웹에서 자주 사용되는 기능 중 하나로, 이번 포스트에서는 React에서 목록의 키워드를 스크롤에 따라 강조할 수 있는 기능을 구현해 볼 것입니다.
📌 완성된 결과를 미리보면 다음과 같습니다.
스크롤 이벤트란?
스크롤 이벤트는 웹 페이지의 스크롤바가 움직일 때마다 발생하는 이벤트입니다.
JavaScript에서는 이를 감지하고, 특정 함수나 동작을 실행하는 데 활용할 수 있습니다.
window.scrollY란?
window.scrollY는 웹 페이지의 상단부터 현재 보이는 화면의 상단까지의 거리(픽셀 값)를 반환하는 속성입니다. 즉, 이 값은 사용자가 얼마나 많이 스크롤했는지를 나타내는 척도가 될 수 있습니다.
스크롤 감지 구현하기
1. state 소개 및 초기 세팅
const containerRef = useRef<HTMLDivElement | null>(null);
const keywordRef = useRef<NodeListOf<Element> | null>(null);
const [activeIndex, setActiveIndex] = useState<number | null>(0);
- containerRef: 스크롤 가능한 컨테이너의 참조값 저장하는 state
- keywordRef: 'keyword' 클래스를 가진 모든 엘리먼트의 참조값을 저장하는 state
- activeIndex: 현재 활성화된 키워드의 인덱스를 저장하는 state
컴포넌트가 마운트될 때 .keyword 클래스를 가진 모든 엘리먼트의 참조값을 저장한다.
useEffect(() => {
keywordRef.current = document.querySelectorAll('.keyword');
}, []);
2. 스크롤 이벤트 관련 구현
useEffect(() => {
// 스크롤 이벤트 관련 내용
}, []);
useEffect 안의 내용을 채워봅시다.
(1) DOM 접근
const container = containerRef?.current;
const keyword = keywordRef?.current;
이 부분은 useRef 훅을 통해 생성된 참조를 사용하여 DOM 요소에 직접적인 접근을 시도하는데 containerRef와 keywordRef는 컴포넌트 내의 특정 DOM 요소를 참조하기 위해 사용되고, current 속성은 참조된 DOM 요소 자체를 가리키고 있습니다.
(2) 예외처리
if (!container || !keyword) return;
예외 처리를 위해 early return문을 작성합니다. 만약 둘 중 하나라도 정의되지 않았다면 리턴합니다.
(3) 스크롤 이벤트 리스너 구현
// ...
const containerHeight = container.clientHeight;
const division = containerHeight / (keyword.length * 1.12);
const handleScroll = () => {
const scrollY = container.scrollTop;
if (scrollY >= 0 && scrollY < containerHeight) {
setActiveIndex(Math.floor(scrollY / division));
}
};
// ...
const containerHeight = container.clientHeight;
container 요소의 내부 높이 (키워드 wrapper의 높이)를 containerHeight에 할당하여 저장합니다. clientHeight는 요소의 실제 높이.
const division = containerHeight / (keyword.length * 1.12);
division은 container의 전체 높이를 "키워드 배열의 길이 * 1.12"로 나눈 값입니다. (1.12는 내려오는 감도를 조정할 수 있는 보정 상수로 작성해준 값이고, 키워드 간의 간격이나 여백에 따라 다르게 설정하면 됩니다.)
const handleScroll = () => {
const scrollY = container.scrollTop;
if (scrollY >= 0 && scrollY < containerHeight) {
setActiveIndex(Math.floor(scrollY / division));
}
};
scrollTop을 통해 요소가 수직으로 스크롤된 양을 저장합니다. (요소가 스크롤 되지 않았다면 0임)
여기서 scrollY >= 0 && scrollY < containerHeight은 스크롤의 위치가 container 안에 있는지 확인하는 조건이고, 스크롤 위치가 위에서 지정한 container의 내부에 위치할 때 참이 됩니다.
setActiveIndex(Math.floor(scrollY / division));
현재 스크롤 위치에 있는 키워드 인덱스를 계산하고, 이를 activeIndex 값으로 정합니다.
이를 통해 스크롤 될 때 마다 container 내부의 스크롤 위치를 감지하고 이 위치에 따라 활성화된 인덱스를 반영해 스타일을 다르게 줄 수 있게 됩니다.
container.addEventListener('scroll', handleScroll);
return () => container.removeEventListener('scroll', handleScroll);
마지막으로 컴포넌트가 마운트될 때 스크롤 이벤트 리스너를 추가하고, 언마운트될 때 이 리스너를 제거합니다.
결과
스크롤에 따른 동적인 요소 감지가 가능하게 되었습니다.
'프론트엔드 > Others' 카테고리의 다른 글
Figma의 multiplayer technology works (0) | 2023.06.20 |
---|---|
Client Side Rendering(CSR)과 Server Side Rendering(SSR) (0) | 2022.12.04 |