问题形容
左右联动的成果,在挪动端比拟常见。比方美团外卖中的商家外卖商品抉择。常见的解决方案就是应用 better-scroll 滑屏库去实现。不过偶然 web 端的我的项目也会要做这样的左右联动的成果。本篇文章是在 vue 框架中应用原生 js 来实现相应的成果的。咱们先看一下最终的效果图:
代码附上
代码中的正文写的有思路步骤的。请依照正文思路步骤来。
<template>
<div id="app">
<div class="top">
<h2>vue 应用原生 js 实现 web 端左右滚动联动成果 </h2>
</div>
<div class="bottom">
<!-- 左侧菜单栏 -->
<div class="bottomLeft">
<div
class="leftItem"
v-for="(item0, index0) in leftArr"
:key="index0"
:class="{highLight: whichIndex == index0}"
@click="letItemHighLight(index0)"
>
{{item0}}
</div>
</div>
<!-- 左侧菜单栏对应的右侧的内容 -->
<div class="bottomRight" ref="wrapper">
<div
class="bottomRightContent"
v-for="(item, index) in rightArr"
:key="index"
ref="item"
>
<div class="bottomRightContentHead">{{item.titleOne}}</div>
<div class="bottomRightContentBody">
<el-col :span="8" v-for="(item2, index2) in item.titleTwo" :key="index2">
<span class="circle"></span>
<span class="word">{{item2}}</span>
</el-col>
<!-- 革除一下浮动 -->
<div style="clear: both"></div>
</div>
<div class="bottomRightContentFooter"></div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {data() {
return {
whichIndex: 0, // 动态显示左侧菜单栏高亮
leftArr: [], // 左侧菜单栏的数据
rightArr: [], // 右侧详情展现对应的数据
rightHeightArr: [], // 右侧每一项的高度数组
rightHeightSumArr: [], // 右侧每一项的高度累加数组
r: 0, // 滚动的间隔
};
},
mounted() {
// 第一步,先发申请获取左右两侧的数据,用于渲染出页面,这里咱们模仿一下发申请的数据
this.getLeftArrData();
this.getRightArrData();},
methods: {getLeftArrData() {
let apiLeftArr = [
"西游记",
"三国演义",
"红楼梦",
"水浒传",
"龙族",
"幻城",
"犬夜叉",
"海贼王",
"一拳超人",
"金刚狼",
"钢铁侠",
"灭霸",
"雷神",
"贪玩蓝月",
"梦幻西游",
"王者光荣",
];
this.leftArr = apiLeftArr;
},
getRightArrData() {
let apiRightArr = [
{
titleOne: "西游记",
titleTwo: ["111", "222", "333", "444"],
},
{
titleOne: "三国演义",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "红楼梦",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "水浒传",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "龙族",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "幻城",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "犬夜叉",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "海贼王",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "一拳超人",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "金刚狼",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "钢铁侠",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "灭霸",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "雷神",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "贪玩蓝月",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "梦幻西游",
titleTwo: ["111", "222", "333", "444", "111", "222", "333", "444"],
},
{
titleOne: "王者光荣",
titleTwo: [
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
"111",
"222",
"333",
"444",
],
},
];
this.rightArr = apiRightArr;
// 第二步,左右两侧有数据当前,才会把高度撑起来,才能够计算高度数组。留神先后顺序
// 应用 this.$nextTick() 将回调,也就是计算两个高度数组,提早到下次 DOM 更新循环之后再计算
this.$nextTick(() => {this.getTwoHeightArr();
});
},
getTwoHeightArr() {// console.log("可能为空", this.$refs.item);
this.$refs.item.forEach((item) => {this.rightHeightArr.push(item["offsetHeight"]);
});
let num = 0;
this.rightHeightArr.forEach((item) => {
num = num + item;
this.rightHeightSumArr.push(num);
});
// 第三步,有了高度滚动条当前,就能够绑定滚动事件了
this.bindScrollEvent();},
bindScrollEvent() {
// 第四步,绑定滚动事件,看滚动到那个区间外面,思路就是通过右侧的区间去同步左侧的区间
this.$refs.wrapper.onscroll = () => {
this.r = this.$refs.wrapper.scrollTop;
// 看看浏览器滚动的高度落到那个区间,在那个区间,就让对应的项高亮
const scrollWhichIndex = this.rightHeightSumArr.findIndex((item, index) => {
return (this.r >= this.rightHeightSumArr[index] &&
this.r < this.rightHeightSumArr[index + 1]
);
});
console.log("所在区间",scrollWhichIndex);
// 初始的区间为 -1,所以还让其为第一项,即索引为 0,当用户往下滑动的时候,所以就会
// 始终大于负一,所以就让其加上一和左侧的高亮项对应。if (scrollWhichIndex > -1) {this.whichIndex = scrollWhichIndex + 1;} else {this.whichIndex = 0;}
}
},
// 第五步,当用户点击的时候再让其滚动,因为滚动和高亮是关联的,所以只有管制滚动,就相当于管制高亮。// 滚动的间隔就是,看用户点击的是哪个菜单项的索引,通过索引找到累加数组对应的那一项,// 也就是滚动的间隔。当为第一项的时候边界值要管制一下
letItemHighLight(i) {if (this.rightHeightSumArr[i - 1] == undefined) {this.$refs.wrapper.scrollTop = 0;} else {this.$refs.wrapper.scrollTop = this.rightHeightSumArr[i - 1];
}
},
},
};
</script>
<style lang="less" scoped>
#app {
width: 100%;
height: 100vh;
.top {
width: 100%;
height: 80px;
text-align: center;
line-height: 80px;
background-color: #e9e9e9;
}
.bottom {
width: 100%;
height: calc(100% - 80px);
display: flex;
.bottomLeft {
width: 288px;
height: 100%;
background-color: #eee;
.leftItem {
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
cursor: pointer;
}
.leftItem:hover {background-color: #dfe3f1;}
.highLight {background: #dfe3f1;}
}
.bottomRight {width: calc(100% - 288px);
height: 100%;
box-sizing: border-box;
padding: 36px 36px 0 36px;
overflow-y: auto;
.bottomRightContent {
width: 100%;
box-sizing: border-box;
padding-bottom: 36px;
.bottomRightContentHead {
height: 25px;
font-family: PingFang SC;
font-style: normal;
font-weight: 600;
font-size: 24px;
line-height: 25px;
text-transform: capitalize;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 32px;
}
.bottomRightContentBody {
.el-col {
position: relative;
margin-bottom: 18px;
.circle {
display: inline-block;
width: 6px;
height: 6px;
background: #4677f6;
border-radius: 50%;
position: absolute;
top: 8px;
left: 0;
}
.word {
margin-left: 12px;
font-family: PingFang SC;
font-style: normal;
font-weight: normal;
font-size: 14px;
color: #4677f6;
cursor: pointer;
}
.word:hover {text-decoration: underline;}
.topPlace {
position: absolute;
top: 1px;
margin-left: 8px;
}
}
}
.bottomRightContentFooter {
height: 1px;
width: 100%;
margin-top: 14px;
background-color: #e9e9e9;
}
}
}
}
}
</style>
总结
实现形式有很多种,我写的这种仅供参考。如有我写的不清晰的,欢送私信或文章评论。与大家共同进步