<a/>
태그의 href
기능을 사용해 스크롤을 목차에 맞게 이동하는 기능만 들어가 있었다.<a href="#List(리스트)">List(리스트)</a>
...
<div id="List(리스트)" >List(리스트)</div>
문서의 제목만을 id값으로 가지는 것이 아니라 구분 할 수 있는 unique한 값이 있으면 좋겠다고 생각했다.
여기서 독특한 값을 생각해보면 해당 목차가 있는 줄의 위치는 무조건 다르다는 특성이 있다.
<a href="#List(리스트)-62">List(리스트)</a>
...
<div id="List(리스트)-62" >List(리스트)</div>
componentDidMount() {
window.addEventListener('scroll',this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll',this.handleScroll);
}
...
@computed
private get isFocusHead() {
return this.distance< 70 && this.distance>0;
}
@action
private handleScroll = () => {
const {children = [],node={},level = -1} = this.props;
const line = node.position.start.line;
if (level>0 && level <4) {
const target = document.getElementsByClassName(`${this.props.children.join("")+ "-" + this.props.node.position.start.line}`)[0];
const clientRect = target.getBoundingClientRect();
const relativeTop = clientRect.top;
this.distance = relativeTop;
if (this.isFocusHead) {
this.inject.resourceStore.setFocusHeadClassName(children.join("") + "-" + line);
}
}
}
스크롤이 이벤트가 발생하면 실행할 handleScroll 함수를 만든다.
level은 markdown에서 h1 h2 ... 를 의미한다. 원하는 header를 가지기 위해 조건문을 추가했다.
관찰하고자 하는 target 을 가져온후 뷰포트 기준에서 상대적인 위치를 가져온다.
자신이 원하는 범위에 target이 들어오다면 target의 이름을 store에 올려준다.
스토어에 올린 이유는 마크다운을 보여주는 컴포넌트와 목차를 보여주는 컴포넌트가 한 부모에 속해있지 않기 때문에 상태관리 store에 올려 관찰하였다.
마지막으로 목차에서 store에 있는 클래스이름과 목차 클래스이름과 같을때 css 작업을 더해주면 스크롤에 따른 목차 하이라이트가 완성되었다.