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>