1. 목차 - PC

출처 : Tistory Blog

출처 : Tistory Blog

Tistory Blog처럼 부드러운 목차를 구현하고 싶었습니다.

1. 요구 사항

  1. 스크롤을 이동할 때 스크롤 위치에 따라 현재 활성화된 목차가 변한다.
  2. 목차에서 해당하는 제목을 누르면 해당 제목으로 이동한다.

2. Intersection-Observer

현재 화면에서 보이는 돔을 바탕으로 목차 활성화 상태가 바뀌므로 intersection-observer을 이용하면 제격이라 판단하였습니다. Heropy님의 Blog 글을 읽어 그림으로 쉽게 설명되어 있어 이해하는 데 큰 도움이 되었습니다.

우선, 제 블로그는 h1태그를 대주제의 제목, h2태그를 소주제의 제목으로 설정하였습니다. 그래서, document.querySelectorAll(’h1, h2’)를 이용하여 현재 페이지의 모든 h1와 h2태그를 찾습니다. 그리고 observer.observer에 등록을 하여 IntersectionObserver가 관찰할 수 있도록 합니다.

useEffect(()=>{
	const observer = new IntersectionObserver(
		// observer에 대한 설정
	)
	const headingElementList = Array.from(document.querySelectorAll('h1, h2'));
	headingElementList.map(header => {
		observer.observe(header)
	}
},[])

observer에 관찰하고 싶은(목차에 들어갈) 각 요소들을 등록을 하였다면 위 주석 부분에 observer에 대한 설정을 해주어야 합니다. 이 부분에서 저희가 할 일은 다음과 같습니다.

  1. 스크롤을 지나갈 때, 가장 상단에 있는 요소가 활성화 된다.

3. scroll 방향 판단하는 함수

let direction: 'up' | 'down';
let prevYPosition = 0;

const checkScrollDirection = (prevY:number) => {
  if(window.scrollY === 0 && prevY === 0) return;
  else if(window.scrollY>prevY) direction = 'down';
  else direction = 'up';
  prevYPosition = window.scrollY;
}

prevYPosition(이전 scroll의 y값)을 넘겨서, 현재 window.scrollY(scroll의 y값)이 이전 prevYPosition보다 크다면 스크롤 방향이 내리는 중, 아니라면 올리는 중이라고 판단합니다.

4. scroll 방향에 따라 목차 활성화

관찰 대상이 루트 요소와 교차 상태로 들어가거나(true) 교차 상태에서 나가는 지(false)여부를 판단하는 isIntersecting 프토퍼티를 이용하였습니다.