效果如下:
代码如下:
<template>
<div class="tabs-container">
<div class="tabs-header">
<div v-for="tab in tabs" :key="tab.name" class="tab" @click="handleTabClick(tab)" ref="tabRefs" :data-tab-name="tab.name">
{{ tab.name }}
</div>
<div class="slider" :style="sliderStyle"></div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
const props = defineProps({
tabs: {
type: Array,
required: true
},
defaultActive: {
type: String,
default: ""
}
});
const activeTab = ref(props.defaultActive || props.tabs[0].name);
const tabRefs = ref([]);
const getActiveTabElement = () => {
return tabRefs.value.find(tab => tab.dataset.tabName === activeTab.value);
};
const sliderStyle = computed(() => {
const activeTabElement = getActiveTabElement();
if (activeTabElement) {
const { offsetLeft, offsetWidth } = activeTabElement;
return {
transform: `translateX(${offsetLeft}px)`,
width: `${offsetWidth}px`
};
}
return {};
});
const emit = defineEmits(["change"]);
const handleTabClick = tab => {
if (activeTab.value !== tab.name) {
activeTab.value = tab.name;
emit("change", tab);
}
};
</script>
<style lang="scss" scoped>
.tabs-container {
position: relative;
user-select: none;
background: rgb(255 255 255 / 20%);
border-radius: 30px;
display: inline-block;
overflow: hidden;
}
.tabs-header {
display: flex;
position: relative;
}
.tab {
padding: 4px 12px;
cursor: pointer;
position: relative;
color: #ffffff;
font-weight: 500;
font-size: 14px;
z-index: 999;
}
.slider {
position: absolute;
bottom: 0;
height: 100%;
background-color: #2578f2;
transition: transform 0.3s ease, width 0.3s ease;
border-radius: 30px;
}
.tabs-content {
padding: 10px;
}
</style>
使用方式:
<template>
<Tabs :tabs="tabsList" @change="tabChange"></Tabs>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Tabs from "@/components/Tabs/index.vue";
interface IInfo {
id: number;
name: string;
}
const tabsList = ref<Array<IInfo>>([
{
id: 1,
name: "标签1"
},
{
id: 2,
name: "标签2"
},
{
id: 3,
name: "标签3"
}
]);
const tabChange = (info: IInfo) => {
console.log(info);
};
</script>