차례창에 다음과 같은 기능을 구현하고자 합니다.
1. 포스트의 제목과 소주제들이 나열된다.
2. 소주제를 누르면 소주제의 위치로 이동한다.
3. 유저가 읽고 있는 부분을 차례창에서 굵게 표시한다.
구현
기능 구현은 javascript 를 이용하였습니다. 우선 PostContentsList 라는 클래스를 만들고 저번에 만든 contents-list div 를 querySelector 로 불러왔습니다. 저는 이 DOM 을 wrapper 라고 부르겠습니다. 이제 wrapper 에다가 차례창 기능을 구현하도록 하겠습니다.
저의 포스트의 제목은 h3 태그를 사용하고 소주제들은 크기에 따라 h3, h4, h5 태그를 이용하여 나타냅니다. 제목과 소주제들을 나열하기 위하여 querySelectorAll 로 post 안의 모든 h3, h4, h5 DOM 을 불러온 후 wrapper.innerHTML 에 적절히 추가하는 방식으로 구현하였습니다.
소주제를 누르면 소주제의 위치로 이동하기 위하여 위의 for loop 에서 각각의 소주제에 id 를 주고 a 태그의 href 속성에 해당 id 위치로 이동하게 설정하였습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classPostContentsList{this.wrapper=document.querySelector('.contents-list');this.contents=document.querySelectorAll('h3, h4, h5');for(leti=0;i<this.contents.length;i++){this.contents[i].id=String(i);// id 추가// a 태그에 href 속성 추가this.wrapper.innerHTML+=`
<a href='#${i}'>
${this.contents[i].innerText}
</a>
<br>`}}
3. 유저가 읽고 있는 부분을 차례창에서 굵게 표시
우선 유저가 읽고 있는 부분이 뭔지 정의하겠습니다. 저는 유저가 어떤 소주제 A 를 읽는다고 했을 때 A 소주제 제목이 viewport 최상단에 나올 때부터 다음 소주제의 제목이 viewport 최상단에 나올 때까지를 유저가 읽고 있는 부분이라고 정의하겠습니다.
이제 구현하겠습니다. 저는 window 에 scroll event 를 추가하는 방식으로 구현했습니다. scroll event 는 소주제들의 제목의 위치와 현제 viewport 의 위치를 비교하여 유저가 어떤 글을 읽고있는지 알아내고, 유저가 읽고있는 소주제 링크에 bold 클래스를 추가하는 방식으로 동작합니다. 코드는 아래와 같습니다.
// 새로운 변수 설정// 소주제 링크들을 저장하는 변수this.contentsList=document.querySelectorAll('.contents-list a');// 유저가 지금 보고 있는 링크를 저장하는 변수// + 초깃값 설정this.curContent=this.contentsList[0];this.curContent.classList.add("bold");// 스크롤 이벤트 리스너 추가window.addEventListener('scroll',(event)=>{// 이전에 유저가 보고 있던 링크 해제this.curContent.classList.remove("bold");// 현재 viewport 위치letcurY=window.pageYOffset;for(vari=1;i<this.contents.length;i++){// 각각의 소주제 위치와 viewport 의 위치 비교if(curY<this.contents[i].offsetTop){// 결과 반영this.curContent=this.contentsList[i-1];this.curContent.classList.add("bold");return}}// viewport 가 마지막 소주제보다 아래에 있을 때 결과 반영this.curContent=this.contentsList[i-1];this.curContent.classList.add("bold");})