vant移动端实现tab锚点定位和tab随滚动条自动切换

我们先实现锚点定位,锚点定位需要借助scrollIntoView方法,这个方法会把当前元素的顶部定位到所在有滚动条的父元素的顶部,从而实现锚点定位的功能:

<style>
    .box {
      width: 500px;
    }

    .son {
      height: 500px;
      border: 1px solid #ccc;
      overflow-y: auto;
    }

    .sonItem1 {
      height: 400px;
      background-color: skyblue;
    }

    .sonItem2 {
      height: 700px;
      background-color: orange;
    }
  </style>
</head>

<body>
  <div class="box">
    <a href="baidu.com" id="aaa">跳转橙色</a>
    <div class="son">
      <div class="sonItem1">我是浅蓝</div>
      <div class="sonItem2" id="sonItem2">我是橙色</div>
    </div>
  </div>
</body>
<script>
  document.getElementById('aaa').onclick = function (e) {
    e.preventDefault(); // 阻止a标签默认跳转行为
    const dom = document.getElementById('sonItem2')
    dom.scrollIntoView()
  }
</script>

注:上面不一定要使用a标签来点击定位,其他标签的点击也是可以的,这里用是因为a标签自带点击的手势图标;
实现锚点定位并不难,只需要用scrollIntoView方法,接下来要实现滚动条滚动到哪个元素的顶部,tab就对应切换;
下面先了解几个方法的区别:scrollTopscrollHeightclientHeightoffsetTop
在这里插入图片描述
clientHeight:带有滚动条盒子的高度
scrollHeight:带有滚动条盒子里面的滚动内容的高度
scrollTop:滚动内容被卷入的高度
offsetTop:元素顶部距离父级元素顶部的高度
判断滚动条触底:scrollHeight=scrollTop+clientHeight
判断某个元素的顶部是否到底滚动盒子的顶部:scrollTop=offsetTop-滚动条盒子距离浏览器顶部的距离(这样就可以计算出每个盒子距离带有滚动条盒子顶部的距离)
在这里插入图片描述

完整的代码示例:

<template>
  <div class="container">
    <div class="box">
      <div class="tab">
        <div class="tab_item" v-for="(item, index) in tabData" :key="item.id">
          <a href="" @click.prevent="handleTab(item.id, index + 1)">
            <div :class="num == index + 1 ? 'active' : ''">
              {{ item.title }}
            </div>
          </a>
        </div>
      </div>
      <div class="info" ref="info">
        <div
          class="info_item"
          v-for="item in tabData"
          :key="item.id"
          :ref="item.id"
        >
          <div style="background: #ffffff">{{ item.title }}</div>
          <div style="height: 500px; background: #ccc"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tabData: [
        { id: '#aaa', title: '基本信息' },
        { id: '#bbb', title: '税务信息' },
        { id: '#ccc', title: '财务信息' },
        { id: '#ddd', title: '供货信息' },
        { id: '#eee', title: '人员信息' },
        { id: '#fff', title: '立案风险' }
      ],
      num: 1
    }
  },
  mounted() {
    this.$refs.info.addEventListener("scroll", this.handleScroll, true);
  },
  methods: {
    handleScroll(e) {
      let t = e.target.scrollTop;//监听的滚动条高度
      let h = e.target.scrollHeight // 滚动高度
      let c = e.target.clientHeight  // 自身高度
      // 获取dom
      const arr = []
      this.tabData.forEach(item => {
        arr.push(this.$refs[item.id][0])
      })
      if (t >= arr[0].offsetTop - 101.5 && t < arr[1].offsetTop - 101.5 && t < (h - c) - 2) {
        this.num = 1
        console.log("1", this.num, t, arr[1].offsetTop - 100.5);
      } else if (t >= arr[1].offsetTop - 101.5 && t < arr[2].offsetTop - 101.5 && t < (h - c) - 2) {
        this.num = 2
        console.log("2", this.num);
      } else if (t >= arr[2].offsetTop - 101.5 && t < arr[3].offsetTop - 101.5 && t < (h - c) - 2) {
        this.num = 3
        console.log("3", this.num);
      } else if (t >= arr[3].offsetTop - 101.5 && t < arr[4].offsetTop - 101.5 && t < (h - c) - 2) {
        this.num = 4
        console.log("4", this.num);
      } else if (t >= arr[4].offsetTop - 101.5 && t < arr[5].offsetTop - 101.5 && t < (h - c) - 2) {
        this.num = 5
        console.log("5", this.num);
      } else if (t >= arr[5].offsetTop - 101.5 && t < (h - c) - 1) {
        this.num = 6
        console.log("6", this.num);
      }
    },
    handleTab(id, num) {
      this.num = num
      console.log("锚点", this.num);
      // 锚点跳转
      this.$refs[id][0].scrollIntoView()
    }
  }
}
</script>

<style lang="scss" scoped>
* {
  box-sizing: border-box;
}
.box {
  width: 500px;
  height: 800px;
  border: 2px solid #ccc;
  background-color: #b2d4eb;
  .tab {
    margin-bottom: 20px;
    background-color: #ffffff;
    display: flex;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 5px;
    .tab_item {
      div {
        border: 1px solid #ccc;
        border-radius: 3px;
        margin-right: 10px;
        padding: 3px;
        height: 30px;
        width: 80px;
        text-align: center;
        line-height: 24px;
        background-color: #d9e4ec;
      }
    }
  }
  .info {
    height: calc(800px - 80.5px);
    // background-color: blue;
    overflow: auto;
    .info_item {
      margin-bottom: 20px;
    }
  }
}
.active {
  background-color: #94bdf5 !important;
  color: #2a72a9;
}
</style>

需要注意的是(难点):当滚动条触底的时候,可能有一些盒子的高度不够,所以到达不了顶部,当继续点击tab的按钮时,会发现有些按钮明明点击了却不选中,是因为点击tab时给num赋值时和if判断里面给num赋值时冲突了,所以要加个t < (h - c) - 2)来判断是否触底了(至于这个2,可能计算不是很准确,需要微调一下),如果触底的话就不执行if判断,tab的选中完全由点击来赋值;
效果如下:
在这里插入图片描述

Vant UI 的 Tab 标签页组件是一个轻量级的导航栏,常用于展示不同类型的内容或者切换视图。如果想要实现锚点跳转到对应标签页的功能,可以按照以下步骤操作: 1. 安装 Vant:首先需要引入 Vant CSS 和 JavaScript 文件,你可以从 Vant 的 GitHub 或者 CDN 上获取。 ```html <link rel="stylesheet" href="https://unpkg.com/vant@latest/dist/index.css"> <script src="https://unpkg.com/vant@latest/dist/vant.min.js"></script> ``` 2. 使用 `<van-tabs>` 组件:创建一个 `<van-tabs>` 元素,并设置每个 `<van-tab>` 代表一个标签页,通常包含一个内部的 `router-view` 或者自定义内容。 ```html <template> <div> <van-tabs v-model="activeIndex"> <van-tab slot="tab" :title="tabs[0].title">Tab 1</van-tab> <van-tab slot="tab" :title="tabs[1].title">Tab 2</van-tab> <!-- 添加更多标签... --> </van-tabs> <router-view ref="view" class="tabpanel-content"></router-view> <!-- 如果使用 Vue Router --> <!-- 或者自定义内容 --> <div v-if="!$refs.view" class="tabpanel-content">{{ tabs[activeIndex].content }}</div> </div> </template> ``` 3. 数据绑定和处理:在 Vue 实例中,维护一个 `tabs` 数组来存储每个标签的信息,包括标题(`title`)和对应的路由路径或内容(`content`)。同时,设置一个 `activeIndex` 变量跟踪当前激活的标签索引。 ```javascript export default { data() { return { tabs: [ { title: '首页', content: '这是首页的内容...' }, { title: '详情', content: '这是详细页面的内容...' }, // 更多... ], activeIndex: 0, }; }, methods: { jumpToTab(tabIndex) { this.activeIndex = tabIndex; // 如果使用 Vue Router,可以在这里添加路由跳转逻辑 this.$router.push({ name: 'yourRouteName', params: { tabIndex } }); } }, }; ``` 4. 跳转功能:你可以为标签按钮添加点击事件,通过 `jumpToTab()` 方法将目标索引传递给 `activeIndex`,然后根据需求进行路由跳转或者直接显示内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值