PC端Tab栏与页面滚动联动(VUE2.0版本)

本文详细描述了如何在VUE2.0应用中实现页面滚动时tab栏自动切换和对应区域滚动到顶部的功能,涉及HTML、CSS和JavaScript代码示例,以及注意事项如处理异步加载和特殊操作对tab状态的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业务背景

一个页面以tab栏作为区块划分时,tab栏与页面彼此间的联动交互,往往能提供更好的体验:点击tab栏时页面滚动到tab栏对应的页面区域,同时滚动页面时tab栏随之改变。

本文基于VUE2.0实现此功能,图例如下:

 HTML部分


<!-- 使用Affix(antd affix)组件固定tab在顶部48px位置上 -->
<!-- getTargetEle确定固定目标元素(需与页面滚动元素一致) -->
<div class="a-container">
  <Affix :offset-top="48" :target="getIdEle">
    <div class="a-tabbar">
      <div
        v-for="(item, index) in tabList"
        :key="item"
        class="a-tabbar-item"
        :class="activeKey === item ? 'a-tabbar-item-active' : ''"
        @click="handleTabClick(item, index)"
      >
        <div class="a-tabbar-item-title">tab栏{{ index }}</div>
        <!-- 分割线显示 -->
        <div v-if="index < tabList.length - 1" class="a-tabbar-item-split"></div>
      </div>
    </div>
  </Affix>
  <div class="a-content">
    <!-- 页面主体 -->
    <div
      class="a-content-item"
      :class="activeKey === item ? 'a-content-item-active' : ''"
      v-for="(item, index) in tabPaneList"
      :key="item"
    >
      <div class="a-content-item-title">tab区域{{ index }}</div>
      <div style="height: 120px"></div>
    </div>
  </div>
  <!-- 返回顶部按钮显示 -->
  <div class="backToTop" @click="backToTop" v-if="showScrollTop">
    <i class="icon iconfont icon-fanhuidingbu"></i>
  </div>
</div>

注:getTargetEle一般不需格外指定,默认为window,本文因样式问题,指定为VUE根DOM——app

JS部分

export default {
  // 引入固钉组件
  components: {
    Affix,
  },
  data() {
    return {
      activeKey: "1",
      tabList: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
      tabPaneList: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
      positionList: [],
      showScrollTop: false,
    };
  },
  mounted() {
    // 页面挂载阶段添加滚动事件、获取滚动位置
    document.getElementById("app").addEventListener("scroll", this.handleScroll);
    this.getScroll()
  },
  methods: {
    getScroll() {
      setTimeout(() => {
        // 重置定位列表
        this.positionList = [];
        const contentList = document.getElementsByClassName("a-content-item");
        const container = document.getElementsByClassName("a-container")[0];
        // 获取默认高度
        const defaultTop = (container.offsetTop ? container.offsetTop : 0) - 61;
        Array.from(contentList).forEach((item) => {
          this.positionList.push(item.offsetTop + defaultTop);
        });
      });
    },
    // tab栏点击时指定页面滚动位置
    handleTabClick(key, index) {
      document.getElementById("app").scrollTop = this.positionList[index];
      this.activeKey = key;
    },
    // 返回顶部
    backToTop() {
      document.getElementById("app").scrollTo({
        top: 0,
        behavior: "smooth",
      });
    },
    handleScroll(e) {
      if (e.target.id === "app") {
        const scrollTop = e.target.scrollTop;
        this.showScrollTop = scrollTop > this.positionList[2];
        // 获取就近tab activeKey
        const findNearIndex = (sT) => {
          let min = null;
          let index = 0;
          this.positionList.forEach((item, i) => {
            const distance = Math.abs(sT - item);
            if (min) {
              if (distance < min) {
                min = distance;
                index = i;
              }
            } else {
              min = distance;
            }
          });
          return index;
        };
        const index = findNearIndex(scrollTop);
        this.activeKey = this.tabList[index];
      }
    },
    getIdEle() {
      return document.getElementById("app");
    },
  },
  beforeDestroy() {
    // 页面注销之前,移除滚动事件
    document.getElementById("app").removeEventListener("scroll", this.handleScroll);
  },

}

本文以VUE根DOM为滚动参考,页面未做特殊配置时,handleScroll事件中前两行写法

 if (e.target.id === "app") {
        const scrollTop = e.target.scrollTop;

                           ↓

if (e.target.scrollingElement.nodeName === "HTML") {

        let scrollTop = e.target.scrollingElement.scrollTop;

handleTabClick事件代码需替换

 document.getElementById("app").scrollTop = this.positionList[index];

                           ↓

 document.documentElement.scrollTop = this.positionList[index];

注: getScroll函数中defaultTop为此功能组件的默认高度,引入组件的位置有时并非在页面最顶端,需要获取默认高度。61为系统顶部菜单栏高度,若系统中无顶部菜单,可忽略

CSS部分


.a-tabbar {
  z-index: 2;
  display: flex;
  background-color: #fff;
  padding: 20px 0;
}
.a-tabbar-item {
  font-family: PingFangSC-Regular;
  font-size: 14px;
  color: #4e5969;
  display: flex;
  align-items: center;
  cursor: pointer;
  &:hover {
    color: #3270ff;
  }
  .a-tabbar-item-split {
    width: 1px;
    margin: 0 12px;
    height: 15px;
    background-color: rgba(184, 188, 196, 1);
  }
}
.a-tabbar-item-active {
  color: #3270ff;
}
.a-content {
  padding-top: 0;
}
.a-content-item {
  margin-top: 32px;
  .a-content-item-title {
    font-family: PingFangSC-Medium;
    font-size: 16px;
    color: #1d2129;
    line-height: 22px;
    font-weight: 600;
    margin-bottom: 16px;
  }
}
.a-content-item:first-child {
  margin-top: 12px;
}
.a-container {
  position: relative;
}
.backToTop {
  width: 40px;
  height: 40px;
  background: #ffffff;
  box-shadow: 0px 0px 14px 0px rgba(0, 0, 0, 0.11);
  border-radius: 27px;
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  right: 32px;
  bottom: 85px;
  z-index: 1;
}

总结

具体实现时,还需注意tab中数据是否为异步加载,以及特殊操作时造成的tab栏与tabpane区域的变动。针对此问题的解决方案为,异步加载的回调函数(promise对象的then属性等)中,或者在特殊操作之后调用getScroll函数,重新获取tab项的定位列表。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值