这篇文章的中心思想呢,就是通过一个变量(flagShow)来控制两个盒子的显示与隐藏(一个是“红框”,另一个是“绿框”),下面我会把重要的部分写在代码的注释上,大家要细心看哦,我们先看一下整体的效果图:
具体效果展示可以看这里https://player.bilibili.com/player.html?aid=460249298
第一步:先来理顺一下结构,为什么要把它放在最上面呢?因为这个功能与结构的布局还是挺关键的
<div class="classify-wrapper">
<div class="left"></div> // 左边那一栏
<div class="right" ref="scroll" @scroll="handleScroll"> // 右边那一栏滚动区域
<div class="top-fixed-title fixed-title" v-show="!flagShow"></div> // 主要!!!标题fixed吸顶(红色区域)
<div class="main-content" v-for="(item, index) in listData" :key="index"> // 右边的每一个模块
<div class="top-title" ref="rightTit">{{item.name}}</div> // 正常的标题(蓝色区域)
<div class="bottom-content"></div> // 内容部分(就是上面图片下面标题的部分)
<div class="fixed-title" v-show="flagShow && index == currentIndex - 1"></div> // 主要!!!原来的吸顶部分现在随着文档流向上滚动(绿色区域)
</div>
</div>
</div>
第二步:参照上面的结构来看看具体的实现逻辑
1. 定义的变量
data() {
listData: [], // 接口获取到的总数据
listHeight: [], // 存放右边模块内容的高度
scrollY: 0, // 右边滚动时的scrollTop
rightTitHeight: 0, // 右边模块标题的高度
currentIndex: 0, // 用于判断左边的高亮以及右边标题的内容显示
flagShow: false, // 控制吸顶的标题 和 不吸顶的标题(显示与隐藏)
}
2. 先把右边每一模块的高度放到一个数组中
getBoxHeight() {
let rightTitHeight = this.rightTitHeight = this.$refs.rightTit.length ? this.$refs.rightTit[0].offsetHeight: 0;
let rightItems = this.$refs.scroll.getElementsByClassName("main-content"); //获取指定类名的所有元素
let height = 0;
this.listHeight.push(height);
for (let i = 0; i < rightItems.length; i++) {
let item = rightItems[i]; // 右边的每一个模块(蓝色标题 + 标题下面所带的内容)
height += item.clientHeight;
this.listHeight.push(height - rightTitHeight); // 把右边模块内容的高度全都放到一个数组中
}
this.listData.forEach((item, index) => {
// 把上面弄的那些高度分别放入总数据中,方便点击左边让右边滚动到所对应的模块
this.$set(item, "distance", this.listHeight[index]);
});
}
3. 滚动的时候判断是否显示影藏那两个标题(红框与绿框)
- this.scrollY >= start:当滚动的scrollTop到达顶部吸顶红框与蓝框的交界处(也就是大于右边模块内容的高度)
- this.scrollY < end:当滚动的scrollTop小于(右边模块内容的高度 加上 右边模块标题的高度)
handleScroll() {
this.scrollY = this.$refs.scroll.scrollTop; // 先获取滚动元素的scrollTop,主要用它来进行判断
for (let i = 0; i < this.listHeight.length; i++) {
let start = this.listHeight[i + 1]; // 右边模块内容的高度
let end = this.listHeight[i + 1] + this.rightTitHeight; // 右边模块内容的高度 加上 右边模块标题的高度
if (this.scrollY >= start && this.scrollY < end) {
this.flagShow = true; // 当满足条件时,红色区域隐藏,绿色区域显示
this.currentIndex = i + 1;
return;
}
this.flagShow = false; // 默认红色区域定位在顶部
}
},
4. 点击左边标题联动右边
通过scrollTop来让右边区域随着左边的点击而联动
changeModel(index) {
this.$refs.scroll.scrollTop = this.listData[index].distance + this.rightTitHeight;
this.currentIndex = index;
}
第三步:结合上面所说,来看一下样式部分
.classify-wrapper {
width: 100%;
height: 100vh;
background: #f7f7f7;
.left {
width: 111px;
height: 100%;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.right {
position: relative;
flex: 1;
width: 100%;
height: 100%;
background: #fff;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
.top-fixed-title { // !!!重要 红色区域
position: fixed !important;
top: 0 !important;
z-index: 999 !important;
background: #f00 !important;
}
.fixed-title { // !!!重要 绿色区域
position: absolute;
bottom: 0;
z-index: 999;
width: 249px;
height: 45px;
background: #0f0;
}
.main-content {
position: relative;
width: 100%;
height: 100%;
.top-title {
height: 45px;
background: #00f; // !!! 重要 蓝色区域
}
}
}
}
以上就是这节的全部内容,欢迎各位大佬在下方评论区提问,如有不足,还望多多指教