TOC라는 개념을 이번 사이드 프로젝트를 하며 알게되었다.
Table of Contents의 약자로 직역하면 목차이다.
포스팅 옆에 보면 목차가 있고,
그 목차를 클릭하면 그 컨텐츠로 스크롤이 이동하는 기능을 자주 보았을 것이다.
그 기능을 구현하는 것이 이번 스프린트에서 내가 할 일이었다.
전제 : 포스팅을 발행하면 DB에 HTML태그가 string으로 저장되며, 각 태그들은 유니크한 id값을 가짐
순서 :
1. DB에 저장된 string형태의 html 태그들 중 h1~h3 태그만 선택한다.
2. 가져온 h태그들이 목차가 된다.
3. 목차를 클릭하면 해당 내용이 있는 곳으로 스크롤 이동
4. 스크롤을 하다가 h태그를 만나면 해당 목차 강조
STEP 1.
DOMParser() 객체를 생성 후 parseFromString 메서드 사용
DOM String (DOM의 문자열형태)을 인자로 받아 DOM 객체를 반환한다.
querySelecterAll 메소드를 사용하여 h1~h3까지 태그를 모두 선택
querySelecterAll 의 반환값은 NodeList로 배열과 유사하지만 배열은 아니다.
➡️ 따라서, 배열 메소드 사용불가 (ex. map, filter 등)
선택한 h태그들을 순회하며 본문, 태그명, id값을 추출하여 객체 배열을 생성
text는 각 목차의 제목을, tag는 목차의 들여쓰기 기준을, 그리고 id는 스크롤의 위치를 나타낸다.
※STEP 2.
useScrollPostition이라는 커스텀 Hooks를 만들었다.
useEffect 를 사용해 페이지가 렌더링되면 스크롤 이벤트를 등록하고, 페이지를 벗어나면 제거한다.
scrollToEl은 TOC의 제목을 클릭하면 해당 태그가 있는 곳으로 스크롤을 이동하는 이벤트이다.
하지만, 태그에 랜덤 id값을 추가하기 이전 코드라서 로직이 이상하다. 지금은 id로 바로 구분이 가능하지만 이전 코드에서 그나마 태그들의 순서를 구별할 수 있는 값이 제목(textcontents)뿐이라 직접 순회하며 비교했었다.
※STEP 3.
포스팅을 읽으면서 스크롤을 내릴 때 옆에 있는 TOC의 제목이 강조되는 것을 본 적이 있을 것이다.
이렇게 동작하는 이벤트 함수를 직접 만들 것이다.
요약하자면, 현재 스크롤의 위치와 h1~h3의 Y축 위치값을 비교하는 것이다.
현 스크롤 위치보다 큰 최초의 태그를 활성화 시켜 유저가 보고 있는 영역이라고 가정하는 것이다.
복잡해보이지만 결국 activeItemId 가 리턴하는 것은 스크롤 위치보다 큰 첫번째 태그의 아이디값이다.
그리고 적용은 위와 같이 특정 조건을 만족할 때 class값을 삽입하는 형태로 했다.
참고