这个效果花了两天的时间,终于实现 ,可以点击快速定位,也可以滑动左侧对应高亮
主要用到a标签的动态锚点,scrollIntoView方法,监听元素的滚动事件
实现方式以我理解的如下:
通过a标签的href属性与其他元素(如div)的id相对应,给a链接加点击事件,让点击的id等于容器的id,实现“id”定位,因为用了div包裹a标签 并且for循环,所以好像不用写href属性,有key就行了。
因为项目里大量使用此功能,为了方便,所以把左侧菜单列表进行了封装,其实也可以都写在父组件中,不用慌,我会把思路都捋一遍
子组件
=-=-=在子组件里循环的rightBlocks,在父组件中是数组,用来装左侧菜单列表的id和name
=-=-= a标签的类名就是给选中项加高亮的样式
=-=-=a标签点击事件中赋值和使用scrollIntoView方法
<template>
<div class="box-left-position" ref="boxPosition" >
<div class="left-content">
<div class="arrowBox" >
<div v-for="(item, index) in rightBlocks" :key="index">
<a :class="rightId === item.id ? 'arrow-a-border' : ''" @click.stop="scrollHome(item.id)">{{ item.name }}</a>
</div>
</div>
</div>
</div>
</template>
props: {
// 导航的项
enterOptions: {
type: Array,
},
},
data() {
return {
//导航的数据
rightBlocks: [],
//右侧内容id
rightId: 'a1',
}
},
/** 点击快速定位 */
scrollHome(id) {
this.rightId = id
document.getElementById(id).scrollIntoView({
block: 'start',
behavior: 'instant',
})
},
父组件
给对应内容区的标题(头部容器)加id,我的布局不是这样,我只是把所有的头部都单独拿出来示范
<!-- 左侧的导航组件 -->
<LeftQuickEnter :enterOptions="rightBlocks" ref="leftQuick"/ >
<!-- 右侧的内容区 -->
<div slot="header" class="clearfix cardTitle" id="a1">
<span style="float: left">xxx标准</span>
</div>
<div slot="header" class="clearfix cardTitle" id="a2">
<span style="float: left">xxx标准</span>
</div>
<div slot="header" class="clearfix cardTitle" id="a3">
<span style="float: left">xxx标准</span>
</div>
<div slot="header" class="clearfix cardTitle" id="a4">
<span style="float: left">xxx标准</span>
</div>
<div slot="header" class="clearfix cardTitle" id="a5">
<span style="float: left">xxx标准</span>
</div>
<div slot="header" class="clearfix cardTitle" id="a6">
<span style="float: left">xxx依据</span>
</div>
在data中定义rightBlocks数组
// 左侧导航的数据
rightBlocks: [
{ id: 'a1', name: 'xxx标准' },
{ id: 'a2', name: 'xxx标准' },
{ id: 'a3', name: 'xxx标准' },
{ id: 'a4', name: 'xxx标准' },
{ id: 'a5', name: 'xxx标准' },
{ id: 'a6', name: 'xxx依据' },
],
将元素滚动到浏览器窗口的可视区域内
主要用到以下的behavior和blcok属性
在子组件的点击事件里使用,过渡动画原先用的是smooth,这里有个坑,就是点击的时候不顺滑,会有抖动及闪现的问题出现,这是因为使用了原生的监听事件,也就是鼠标滚动事件和这个冲突了,改成instant之后就没有这个问题了
子组件
/** 点击快速定位 */
scrollHome(id) {
this.rightId = id
document.getElementById(id).scrollIntoView({
block: 'start',
behavior: 'instant',
})
},
这是比较重点的一块,正常是监听浏览器滚动事件,即
父组件
//在mounted中
window.addEventListener('scroll', this.scrollList, true); // 监听(绑定)滚动条滚动事件
这里也有坑,花了我半天时间排查,我绑了事件后,在对应的方法里获取滚动条被卷去的高度,即
父组件
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
我怎么打印scrollTop 的结果都是0,然后我又去百度为什么结果是0,网上的解释大致是页面是否具有DTD(DOCTYPE),document.documentElement.scrollTop和document.body.scrollTop必定有一个有值,写||,就能拿到任意有值的那一个,但是我这么写了还是0。
后来才发现,是因为布局的原因,我的滚动条不是浏览器的,是容器的。
给容器绑滚动事件,你哪个容器产生了滚动条,就给哪个绑。
父组件
let that = this
document.getElementById('box').addEventListener('scroll', that.scrollList, true)
},
给每个内容区的盒子,加id
父组件
<div id="carda">
<div slot="header" class="clearfix cardTitle" id="a1">
<span style="float: left">xxx标准</span>
</div>
<div>内容xxxx </div>
<div>
<div id="cardb">
<div slot="header" class="clearfix cardTitle" id="a1">
<span style="float: left">xxx标准</span>
</div>
<div>内容xxxx </div>
<div>
其他省略........
然后就是在scrollList方法中写实现的代码了,这里要说一下用准备的东西了
首先要拿到有滚动条的容器的scrollTop,就是滚动条距离顶部的距离
然后拿到每个内容区的盒子距离父元素顶部的距离offsetTop,如果父元素有定位,这个offsetTop就是内容盒子顶部到父盒子顶部的距离,如果父元素没有定位,就是内容盒子顶部到文档顶部的距离。
拿到这些后,如果滚动条滚动距离在这个距离里就让它高亮的菜单
父组件
scrollList() {
//获取滚动条到顶部的距离
let scrollTop = document.getElementById('box').scrollTop
// 获取右侧每个盒子距离顶部的高度
let height1 = document.getElementById('carda').offsetTop
let height2 = document.getElementById('cardb').offsetTop
let height3 = document.getElementById('cardc').offsetTop
let height4 = document.getElementById('cardd').offsetTop
let height5 = document.getElementById('carde').offsetTop
let height6 = document.getElementById('cardf').offsetTop
if (scrollTop < height1 && scrollTop >= 0) {
this.$refs.leftQuick.rightId = 'a1'
} else if (scrollTop > height1 && scrollTop < height2) {
this.$refs.leftQuick.rightId = 'a2'
} else if (scrollTop > height2 && scrollTop < height3) {
this.$refs.leftQuick.rightId = 'a3'
} else if (scrollTop > height3 && scrollTop < height4) {
this.$refs.leftQuick.rightId = 'a4'
} else if (scrollTop > height4 && scrollTop < height5) {
this.$refs.leftQuick.rightId = 'a5'
} else if (scrollTop > height5) {
this.$refs.leftQuick.rightId = 'a6'
}
},
应该没有漏掉的,有问题欢迎提问~~~~~~~~~~~~~·