这篇文章的中心思想呢,就是通过一个变量(flagShow)来控制两个盒子的显示与隐藏(一个是“红框”,另一个是“绿框”),下面我会把重要的部分写在代码的注释上,大家要细心看哦,我们先看一下整体的效果图:


效果演示


第一步:先来理顺一下结构,为什么要把它放在最上面呢?因为这个功能与结构的布局还是挺关键的
<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. 滚动的时候判断是否显示影藏那两个标题(红框与绿框)
  1. this.scrollY >= start:当滚动的scrollTop到达顶部吸顶红框与蓝框的交界处(也就是大于右边模块内容的高度)
  2. 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; // !!! 重要 蓝色区域
      }
    }
  }
}

以上就是这节的全部内容,欢迎各位大佬在下方评论区提问,如有不足,还望多多指教