vue:实现锚点双向滚动/文章章节联动滚动效果
vue实现锚点双向滚动/章节联动效果
·
需求描述
需要实现类似doc中文档大纲的效果,点击对应章节的名称时定位到相应的正文;而当正文滚动时,高亮显示对应的章节名称
实现思路
其实笔者一开始想到的是利用a标签页内跳转(也就是“锚点”),类似于Element-UI官方文档:单选框组
当鼠标悬浮到页内某一章节名称时,会显示符号为“¶”的锚点,点击锚点会在网页链接后拼接对应hash值实现页内跳转
但仅靠锚点难以实现滚动页面内容时,定位到对应章节名称。。还是得靠度娘
经过了一番搜索与尝试,我发现所有标注了“vue锚点双向滚动”的文章实际都采用了监听滚动/滚动页面的实现思路和“锚点”其实并无关联。。,总之,笔者最终翻到了这篇锚点双向定位博客,虽然原文的示例代码稍显粗糙,但这篇的本质其实就是经过个人润色的那篇博客哦☆♦☆!
示例代码
请在你本地引入了Element-UI的项目中,新建一个test.vue来运行以下示例代码~
<!--
* @Author: smm
* @Date: 2022-09-19 15:33:32
* @LastEditors: smm
* @LastEditTime: 2022-09-19 17:27:08
* @Description: 章节联动滚动示例
-->
<template>
<div class="sectionTest">
<div>
<el-radio-group
v-model="sectionIdx"
@change="change"
>
<el-radio
v-for="(item, index) in sectionList"
:key="item"
:label="index"
>
{{ item }}
</el-radio>
</el-radio-group>
</div>
<div
class="contentBlock"
@scroll="scrollEvent"
>
<div
v-for="item in sectionList"
:key="item"
class="content"
>
{{ `正文:${item}` }}
</div>
</div>
</div>
</template>
<script>
export default {
name: ``,
data () {
return {
sectionList: [`第一章`, `第二章`, `第三章`, `第四章`, `第五章`], // 章节标题列表
sectionIdx: 0 // 当前的章节下标
}
},
methods: {
change () {
let contents = document.querySelectorAll('.content')
contents[this.sectionIdx].scrollIntoView({ block: 'start', behavior: 'smooth' })
},
scrollEvent (e) {
const { sectionList } = this
let contents = document.querySelectorAll('.content')
let nowTop = e.target.scrollTop // 滚动条目前的滚动距离
let firstTop = contents[0].offsetTop // 第一个章节的顶部位置
let idx = null
try { // forEach循环只能通过抛出异常的方式终止
sectionList.forEach((section, index) => {
let contentTop = contents[index].offsetTop // 第index个章节的顶部位置
let scrollDistance = contentTop - firstTop // 从第一个章节到第index个章节的滚动距离
if (nowTop < scrollDistance) {
// 滚动条已滚动的距离少于第index个章节需要的滚动距离,说明当前正文处于第(index-1)的章节
idx = Math.max(0, index - 1)
throw new Error(`find section:${this.sectionIdx}`)
}
})
} catch (e) { }
// 滚动到最后一章(该章节高度超过正文容器)时,滚动条的滚动距离超过所有章节需要的滚动距离
this.sectionIdx = idx === null ? sectionList.length - 1 : idx
if (e.srcElement.scrollTop + e.srcElement.offsetHeight === e.srcElement.scrollHeight) {
// 滚动条触底,处于最后一章(消除该章节高度低于正文容器时始终定位在倒数第二章的情况)
this.sectionIdx = sectionList.length - 1
}
}
}
}
</script>
<style lang="scss">
.sectionTest {
height: 500px;
background: #fff;
padding: 0 20px;
.contentBlock{
height: 400px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 10px;
height: 10px;
}
&::-webkit-scrollbar-thumb {
background:#ccc;
border: 1px solid green;
border-radius: 5px;
}
&::-webkit-scrollbar-track {
background: #666;
border-radius: 5px;
}
}
.content {
border: 1px solid red;
margin: 10px 0;
color: orangered;
&:nth-child(even) {
height: 500px;
background: #aaa;
}
&:nth-child(odd) {
height: 300px;
background: #eee;
}
}
}
</style>
参考网址
[1] 锚点双向定位
[2] Element-UI单选框组
[3] Js中forEach跳出本次循环和终止循环
更多推荐
已为社区贡献4条内容
所有评论(0)