目前用react 写一个toc组件.对于浏览文字类的网站这种目录还是很有帮助的.最基础的功能就类似于掘金的那个.
我在那个基础上加了隐藏和移动位置的功能,就会变得更通用了.
跳转到指定节点
跳转到页面指定元素的位置有一个api, node.scrollIntoView(true)
你只要用想跳转到的dom调用这个函数就可以了.
其中true和false的传参是决定跳转到节点开始处还是结尾的作用.
这样我们只要在react遍历渲染目录列表的时候,每个li都添加一个点击事件跳转到对应的节点位置就可以实现跳转功能了.
滚动条监听
每个dom元素有好几个和位置有关的属性
比如clientHeight,clientLeft,clientRight,clientWidth这几个元素是
- clientLeft和clientRight分别是左右的border大小
- clientWidth和clientHeight 分别是border内部的大小(只包括padding和内容大小)
offsetHeight,offsetTop,offsetLeft,offsetRight
-
offsetLeft和offsetRight,offsetTop是以父元素为参照点,当前元素相对于父元素的偏移量, 比如相对定位的时候的偏移量就能在这里反映出来,是只读属性
- offsetWidth offsetHeight是包含border和内容的
scrollTop,scrollLeft,scrollWidth,scrollHeight
- scrollTop和scrollLeft 是刻度列属性,分别表示水平和垂直两条滚动条滚动的距离
- scrollWidth和scrolltHeight是只读属性,返回当前节点的时机宽度和高度.
addEventListener有一个特性就是同一个事件可以添加多次,但是,同一个事件添加同一个函数的情况只能添加一次,这样就可以利用这一点避免重复添加事件了.
所以我们不应该使用匿名函数和箭头函数,而应该定义出来
关于滚动条的参数,scrollTop是滚动距离比较直观,随着scrollTop的增加,我们的页面跟着滚动,offsetTop是固定值,表示子元素相对父元素的偏移位置,因此offset去除第一个子元素的偏移的部分和滚动距离应该是正比于scrollTop,这样就能随着滚动的百分比,toc中定位到不同标题了
headList就是收集到页面的标题相关的信息的列表,因为一般情况下只需要在组件装载的时候收集一次就行了,所以,这边作为useEffect的引用也没什么影响,基本上只会执行一次。因为addEventListener的参数我们给了一个固定的函数,这也导致,即使多次执行也不会重复添加。
function handleScrollToc() {
// 可视区域高度
// let clientHeight = document.documentElement.clientHeight;
// 滚动内容高度,即页面所有内容的高度
// let scrollHeight =document.documentElement.scrollHeight
// 滚动条已滚动的高度
const scrollTop = document.documentElement.scrollTop
headList.forEach((head: any, index: number) => {
if (scrollTop < head.offsetTop - baseOffset.current) {
return
} else {
setActiveIndex(index)
}
})
}
useEffect(() => {
window.addEventListener('scroll', handleScrollToc)
return () => {}
}, [headList])