vue锚点导航
锚点导航在现实中经常遇到,最常见就是文档之类的网站,比如
vue
官网、react
官网、antd
官方文档等。今天就写一个锚点导航供需要的人参考,本文是基于vue + element-ui
。
💥基础功能
除了页面布局外,只需要几行代码就能实现一个简单的导航,通过scrollIntoView()
,此方法会滚动元素的父容器,使被调用 scrollIntoView() 的元素对用户可见。效果如下:
语法(更详细的介绍可以参考👉MDN Web Docs)
element.scrollIntoView(); // 等同于 element.scrollIntoView(true)
element.scrollIntoView(alignToTop); // Boolean 型参数
element.scrollIntoView(scrollIntoViewOptions); // Object 型参数
参数
alignToTop(可选):
如果为true,元素的顶端将和其所在滚动区的可视区域的顶端对齐。相应的scrollIntoViewOptions: {block: “start”, inline: “nearest”}。这是这个参数的默认值。
如果为false,元素的底端将和其所在滚动区的可视区域的底端对齐。相应的scrollIntoViewOptions: {block: “end”, inline: “nearest”}。
scrollIntoViewOptions(可选)一个包含下列属性的对象:behavior 可选
定义动画过渡效果, "auto"或 “smooth” 之一。默认为 “auto”。block 可选
定义垂直方向的对齐, “start”, “center”, “end”, 或 "nearest"之一。默认为 “start”。inline 可选
定义水平方向的对齐, “start”, “center”, “end”, 或 "nearest"之一。默认为 “nearest”。
<template><el-row :gutter="20"><el-col :span="18"><div class="box-col" id="box"><el-card :id="item.id" class="box-card" v-for="item in navList" :key="item.value"><div slot="header" class="clearfix"><span>{{item.label}}</span></div><div v-for="o in 4" :key="o" class="text item">{{'列表内容 ' + o }}</div></el-card></div></el-col><el-col :span="6"><div class="navBox"><div @click="goAnchor(item.id, item.value)" :class="['navItem', navActive == item.value ? 'active' : '']" v-for="item in navList" :key="item.value">{{ item.label }}</div></div></el-col></el-row>
</template>
<script>
export default {name: "Anchor",data() {return {navActive: 1,navList: [{label: "卡片名称1",value: 1,id: "part1",},{label: "卡片名称2",value: 2,id: "part2",},{label: "卡片名称3",value: 3,id: "part3",},{label: "卡片名称4",value: 4,id: "part4",},{label: "卡片名称5",value: 5,id: "part5",},],};},methods: {// 锚点导航-主要代码逻辑goAnchor(keyId, val) {this.navActive = val;document.getElementById(keyId).scrollIntoView(true);},},
};
</script>
<style scoped>
html {overflow: hidden;
}
.box-col {height: 90vh;overflow-y: auto;box-sizing: border-box;scroll-behavior: smooth;
}
.box-card {height: 500px;margin-bottom: 10px;
}
.navBox {margin-left: 10px;border-left: 2px solid rgba(0, 0, 0, 0.09);
}
.navItem {font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #000000;padding: 10px;margin-left: -2px;cursor: pointer;border-left: 2px solid transparent;
}
.navItem:hover {color: #177be6;
}
.navItem.active {color: #177be6;border-left: 2px solid #177be6;
}
</style>
🔥进阶功能 👉在线运行
现在基础功能已经实现了,处理点击能到指定位置,我们也需要鼠标滚动的时候,锚点也跟着联动,这个有点麻烦,需要监听鼠标滚动事件,先看效果图:
完整js代码如下:
需要注意的一点是,
navClickFlag
标识,因为,点击的时候scrollIntoView(true)
会触发滚动,这个时候执行滚动函数,如果不加的话,锚点active状态会出现抖动,所以添加标识,点击锚点的时候尽量避免滚动函数里的逻辑。
<script>
export default {name: "Anchor",data() {return {//锚点点击标识, 不然active就会来回抖动navClickFlag: false,// 滚动元素idscrollWrap: "box",navActive: 1,navList: [{label: "卡片名称1",value: 1,id: "part1",},{label: "卡片名称2",value: 2,id: "part2",},{label: "卡片名称3",value: 3,id: "part3",},{label: "卡片名称4",value: 4,id: "part4",},{label: "卡片名称5",value: 5,id: "part5",},],// 各锚点的高度offTopLs: [],};},mounted() {// 监听滚动window.addEventListener("scroll", this.handleScroll, true);this.$nextTick(() => {// 计算锚点的高度this.getoffTop();});},beforeDestroy() {// 销毁监听window.removeEventListener("scroll", this.handleScroll);},methods: {// 计算锚点的高度getoffTop() {let offTop = [];for (let index = 0; index < this.navList.length; index++) {const element = this.navList[index];if (document.getElementById(element.id)) {offTop.push(document.getElementById(element.id).offsetTop);}}this.offTopLs = offTop;},// 监听滚动handleScroll() {if (!this.navClickFlag && document.getElementById(this.scrollWrap)) {let scTop = document.getElementById(this.scrollWrap).scrollTop;for (let index = 0; index < this.offTopLs.length; index++) {const element = this.offTopLs[index];let offsetTop = document.getElementById(this.scrollWrap).offsetTop;if (scTop + offsetTop >= element) {this.navActive = index + 1;}}}},// 锚点导航goAnchor(keyId, val) {this.navClickFlag = true;this.navActive = val;document.getElementById(keyId).scrollIntoView(true);setTimeout(() => {this.navClickFlag = false;}, 2000);},},
};
</script>