vue 自定义 tabs 控件,可自动左右滑动使得选中项居中显示

效果图如下:

录屏如下:

tabs录屏

控件用法如下:

<navi-tabs :data="tabs" @changeTab="changeTab"></navi-tabs>

import NaviTabs from "@/components/navi-tabs";

components: { NaviTabs },

tabs: [
  { codeName: "菜单1" },
  { codeName: "菜单2" },
  // { codeName: "菜单..." },
  { codeName: "菜单N" },
],
currentTabIndex: 0,

changeTab(index) {
  this.currentTabIndex = index;
  // this.refreshTargetTabPage();
},

控件源码如下:

<template>
  <div class="tabs-root">
    <div class="tabs-container">
      <div class="tabs" ref="tabs" v-if="data && data.length > 0">
          <div class="item" v-for="(tab, index) in data" :key="index"
            :class="activeIndex == index ? 'active': ''"
            @click="setActiveIndex(index)">
            {{ tab.codeName }}
          </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      default: [],
    },
  },
  data() {
    return {
      activeIndex: 0, // 默认激活的tab索引
    };
  },
  mounted() {
    this.scrollToActiveTab(); // 初始化时也滑动到第一个tab
  },
  methods: {
    setActiveIndex(index) {
        this.activeIndex = index;
        this.$emit("changeTab", index);
        this.scrollToActiveTab(); // 调用滑动函数
    },
    scrollToActiveTab() {
      this.$nextTick(() => {
        if (this.activeIndex == 0) {
          tabs.scrollTo({ left: 0, behavior: 'smooth' });
          return;
        }
        const tabs = this.$refs.tabs;
        const tabsRect = tabs.getBoundingClientRect();
        const activeTab = tabs.children[this.activeIndex];
        const activeTabRect = activeTab.getBoundingClientRect();
        let widthBeforeAll = 0;
        for (let index = 0; index < this.activeIndex; index++) {
          const element = tabs.children[index];
          const elementsRect = element.getBoundingClientRect();
          widthBeforeAll += elementsRect.width;
        }
        const offSetX = widthBeforeAll + (activeTabRect.width / 2) - (tabsRect.width / 2);
        tabs.scrollTo({ left: (tabsRect.left / 2 + offSetX), behavior: 'smooth' });
      });
    }
  },
};
</script>
<style lang="scss" scoped>
  .tabs-root {
    width: 100%;
    height: 44px;
    display: flex;
    justify-content: center;

    .tabs-container {
      width: auto;
      height: 100%;
      overflow-x: hidden;
      overflow-y: hidden;

      .tabs {
        display: flex;
        flex-direction: row;
        align-items: center;
        overflow-x: auto;

        .item {
          min-width: 120px;
          height: 26px;
          margin-top: 9px;
          margin-bottom: 9px;
          margin-right: 9px;
          cursor: pointer;
          white-space: nowrap;
          font-family: PingFangSC-Semibold;
          font-size: 18px;
          color: #FFFFFF;
          text-align: center;
          line-height: 26px;
          font-weight: 600;
          background: #C70019;
          border-radius: 13px;
        }
        .active {
          background: #DD6675;
        }
      }
    }
  }
</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

却染人间愁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值