概要:我们在实现自己的文章或者文档的时候,章节菜单是必不可少的,点击菜单中的章节,页面滚动到对应位置。页面滚动到章节所属位置后,对应的菜单也该高亮显示。让我们来看看怎么实现这个需求吧。
基础知识
- Window.scrollY:返回文档在垂直方向已滚动的像素值。
- e.scrollTop: 获取或设置元素内容从其顶部边缘滚动的像素数(针对容器的滚动距离,值不一定是整数)。
- e.offsetTop: 返回当前元素相对于其
offsetParent
元素的顶部内边距的距离。
- e.offsetHeight: 返回该元素的像素高度,高度包含该元素的垂直内边距和边框(值为整数)。
- e.scrollIntoView: 滚动容器,使元素在容器中对用户可见,可以设置平滑滚动
smooth
,顺时滚动instant
,自动计算auto
。
- IntersectionObserver: 交叉观察器,用来监听可见区域的特定变化值,可以在同一个观察者对象中配置监听多个目标元素,详细可查阅MDN。
方案1:使用交叉观察器
用法相当简单明了,先配置和写出超过指定阈值后调用的回调函数,然后给需要观察的元素都观察上即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const options = { root: document.querySelector("#scrollArea.scrollbar"), rootMargin: "0px", threshold: 0.5, };
observer.value = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { console.log("章节可见", entry); activeId.value = Number( entry.target.getAttribute("id").replace("title", "") ); } }); }, options); if (props.data.length) { props.data.forEach((item) => { const e = document.querySelector(`#title${item.id}`); if (e) { observer.value.observe(e); } }); }
|
方案2:使用滚动事件
监听容器的scroll事件,拿到容器的滚动距离也就是e.scrollTop
,然后遍历需要观察的章节dom,判断滚动位置是否以达到章节的顶部以及是否未超过章节的顶部,这里也可以做些处理,让章节提前高亮。我因为用了el-scrollbar
,就没有用e.onscroll
,逻辑都是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <el-scrollbar class="scrollbar" id="scrollArea" ref="container" @scroll="updateScroll" > </el-scrollbar>
const updateScroll = ({ scrollTop }) => { notes.value.forEach((sec) => { let offset = sec.offsetTop - 150; let height = sec.offsetHeight; console.log(scrollTop, offset, height); let id = sec.getAttribute("id").replace("wrap", "");
if (scrollTop >= offset && scrollTop < offset + height) { activeId.value = Number(id); console.log("activeId", activeId.value); } }); };
|