Tabs 标签页
标签页组件,用于在不同的内容区域之间进行切换。
组件源码
vue
<script lang="ts" setup>
import { computed } from 'vue';
const $props = withDefaults(
defineProps<{
name?: string;
tabs: { label: string; value: string; dot?: string | number }[];
}>(),
{
name: 'tabs-' + Math.random().toString(36).substring(2)
}
);
const checkedValue = defineModel<string>();
const onChangeTab = (e: Event) => {
const target = e.target as HTMLInputElement;
if (target.tagName === 'INPUT') {
checkedValue.value = target.value;
}
};
const gliderStyle = computed(() => {
const index = $props.tabs.findIndex(
(item) => item.value == checkedValue.value
);
if (index === -1) {
return {
opacity: 0
};
}
return {
transform: `translateX(${index * 100}%)`
};
});
</script>
<template>
<div class="tabs" @click="onChangeTab">
<template v-for="(item, index) in tabs">
<input
type="radio"
:id="`${name}-radio${index}`"
:name
:value="item.value"
:checked="checkedValue === item.value" />
<label class="tab" :for="`${name}-radio${index}`">
{{ item.label }}
<span class="notification" v-if="item.dot">{{ item.dot }}</span>
</label>
</template>
<span class="glider" :style="gliderStyle"></span>
</div>
</template>
<style lang="scss" scoped>
@mixin item {
padding: 2px 4px;
height: 30px;
width: 50px;
border-radius: 17px;
}
$color-light: #185ee0;
$color: #e6eef9;
.tabs {
display: flex;
background-color: #fff;
box-shadow: 0 0 1px 0 rgba(24, 94, 224, 0.15),
0 6px 12px 0 rgba(24, 94, 224, 0.15);
padding: 10px;
border-radius: 99px;
}
.tabs * {
z-index: 2;
}
.tabs input[type='radio'] {
display: none;
}
.tab {
position: relative;
display: flex;
align-items: center;
justify-content: center;
@include item;
font-size: 0.8rem;
color: #000;
font-weight: 500;
cursor: pointer;
transition: color 0.15s ease-in;
}
.notification {
display: flex;
align-items: center;
justify-content: center;
width: 0.8rem;
height: 0.8rem;
position: absolute;
top: -2px;
right: 2px;
font-size: 10px;
border-radius: 50%;
margin: 0px;
background-color: $color;
transition: 0.15s ease-in;
}
.tabs input[type='radio']:checked + label {
color: $color-light;
}
.tabs input[type='radio']:checked + label > .notification {
background-color: $color-light;
color: #fff;
margin: 0px;
}
.glider {
position: absolute;
display: flex;
@include item;
background-color: $color;
z-index: 1;
transition: 0.25s ease-out;
}
</style>基本用法
示例代码
vue
<template>
<div class="container">
<base-tabs :tabs="tabs1" v-model="checkedValue1" />
<base-tabs name="tabs2" :tabs="tabs2" v-model="checkedValue2" />
</div>
</template>
<script lang="ts" setup>
import BaseTabs from '@/BaseTabs/BaseTabs.vue';
import { ref } from 'vue';
const tabs1 = ref([
{ label: 'Tab 1', value: 'tab1' },
{ label: 'Tab 2', value: 'tab2' },
{ label: 'Tab 3', value: 'tab3' }
]);
const checkedValue1 = ref('tab1');
const tabs2 = ref([
{ label: '香蕉', value: '1' },
{ label: '苹果', value: '2', dot: 5 },
{ label: '橘子', value: '3' }
]);
const checkedValue2 = ref('2');
</script>
<style lang="scss" scoped>
.container {
display: flex;
gap: 40px;
}
</style>API
Props
| 参数名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| modelValue(v-model) | 绑定值 | string | - |
| name | 名称 | string | 随机字符串 |
Events
| 事件名 | 说明 | 参数 |
|---|---|---|
| update:modelValue | 切换标签页时触发 | modelValue: string |