标签:控件 vue title label element content targetOffsetTop scrollTop document
树形控件实现定位+平滑滚动(左树形右内容)
vue+element 实现点击左侧树形控件实现右侧滚动定位
具体实现代码如下:
<template>
<div class="detail">
<div class="detail-content">
<div class="detail-content-left">
<div>
<el-tree
:data="data"
:props="defaultProps"
@node-click="handleNodeClick"
/>
</div>
</div>
<div class="detail-content-right">
<div
v-for="(item, index) in list"
:key="index"
class="scroll-item"
@scroll="onScroll"
>
<div>{{ item.title }}</div>
<div>{{ item.content }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
data: [
{
label: "一级 1"
},
{
label: "一级 2"
},
{
label: "一级 3",
children: [
{
label: "二级 3-1",
children: [
{
label: "三级 3-1-1"
}
]
},
{
label: "二级 3-2",
children: [
{
label: "三级 3-2-1"
}
]
}
]
}
],
defaultProps: {
children: "children",
label: "label"
},
list: [
{
title: "1",
content: "1-1"
},
{
title: "2",
content: "2-2"
},
{
title: "3",
content: "3-2"
},
{
title: "1",
content: "1-1"
},
{
title: "2",
content: "2-2"
},
{
title: "3",
content: "3-2"
},
{
title: "1",
content: "1-1"
},
{
title: "2",
content: "2-2"
},
{
title: "3",
content: "3-2"
},
{
title: "1",
content: "1-1"
},
{
title: "2",
content: "2-2"
},
{
title: "3",
content: "3-2"
},
{
title: "1",
content: "1-1"
},
{
title: "2",
content: "2-2"
},
{
title: "3",
content: "3-2"
},
{
title: "1",
content: "1-1"
}
]
};
},
computed: {},
created() {
},
methods: {
handleNodeClick(data) {
this.clickdata = data.$treeNodeId;
console.log(this.clickdata);
this.scrollTo(this.clickdata);
},
// 滚动监听器
onScroll() {
// 获取所有锚点元素
const navContents = document.querySelectorAll(".scroll-item");
// 所有锚点元素的 offsetTop
const offsetTopArr = [];
navContents.forEach(item => {
offsetTopArr.push(item.offsetTop);
});
// 获取当前文档流的 scrollTop
const scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
// 定义当前点亮的导航下标
let navIndex = 0;
for (let n = 0; n < offsetTopArr.length; n++) {
// 如果 scrollTop 大于等于第n个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
// 那么此时导航索引就应该是n了
if (scrollTop >= offsetTopArr[n]) {
navIndex = n;
}
}
this.active = navIndex;
},
// 跳转到指定索引的元素
scrollTo(index) {
// 获取目标的 offsetTop
// css选择器是从 1 开始计数,我们是从 0 开始,所以要 +1
const targetOffsetTop = document.querySelector(
`.scroll-item:nth-child(${index + 1})`
).offsetTop;
// 获取当前 offsetTop
let scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
// 定义一次跳 50 个像素,数字越大跳得越快,但是会有掉帧得感觉,步子迈大了会扯到蛋
const STEP = 50;
// 判断是往下滑还是往上滑
if (scrollTop > targetOffsetTop) {
// 往上滑
smoothUp();
} else {
// 往下滑
smoothDown();
}
// 定义往下滑函数
function smoothDown() {
// 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
if (scrollTop < targetOffsetTop) {
// 如果和目标相差距离大于等于 STEP 就跳 STEP
// 否则直接跳到目标点,目标是为了防止跳过了。
if (targetOffsetTop - scrollTop >= STEP) {
scrollTop += STEP;
} else {
scrollTop = targetOffsetTop;
}
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
// 关于 requestAnimationFrame 可以自己查一下,在这种场景下,相比 setInterval 性价比更高
requestAnimationFrame(smoothDown);
}
}
// 定义往上滑函数
function smoothUp() {
if (scrollTop > targetOffsetTop) {
if (scrollTop - targetOffsetTop >= STEP) {
scrollTop -= STEP;
} else {
scrollTop = targetOffsetTop;
}
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
requestAnimationFrame(smoothUp);
}
}
}
},
destroy() {
// 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
window.removeEventListener("scroll", this.onScroll);
}
};
</script>
<style lang="scss" scoped>
// 此处使用scss如若less改成less即可
.detail {
width: 1009px;
&-content {
display: flex;
justify-content: space-between;
&-left {
background: #fff;
position: relative;
width: 220px;
padding: 10px 0 0 20px;
div {
position: fixed;
background: #fff;
}
}
&-right {
width: 780px;
background: #fff;
margin-left: 9px;
padding: 20px;
}
}
}
</style>
标签:控件,vue,title,label,element,content,targetOffsetTop,scrollTop,document 来源: https://blog.csdn.net/benpaodexiaozhu_/article/details/112644597
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。