|
|
@@ -0,0 +1,123 @@
|
|
|
+<template>
|
|
|
+ <div class="tab-bar">
|
|
|
+ <!-- 区分两种模式:带数量的按钮模式、分段大选项卡模式 -->
|
|
|
+ <div v-if="mode === 'button'" class="tab-group-small">
|
|
|
+ <button
|
|
|
+ v-for="(item, index) in tabList"
|
|
|
+ :key="item.key || index"
|
|
|
+ class="tab-item-small"
|
|
|
+ :class="{ active: currentActive === (item.key || index) }"
|
|
|
+ @click="handleTabClick(item.key || index)"
|
|
|
+ >
|
|
|
+ <span>{{ item.label }}</span>
|
|
|
+ <span v-if="item.count !== undefined && item.count !== null" class="count-badge">({{ item.count }})</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div v-else class="tab-group-large">
|
|
|
+ <button
|
|
|
+ v-for="(item, index) in tabList"
|
|
|
+ :key="item.key || index"
|
|
|
+ class="tab-item-large"
|
|
|
+ :class="{ active: currentActive === (item.key || index) }"
|
|
|
+ @click="handleTabClick(item.key || index)"
|
|
|
+ >
|
|
|
+ {{ item.label }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import { computed } from 'vue';
|
|
|
+
|
|
|
+ const props = defineProps({
|
|
|
+ // 选项卡数据列表,元素包含 label、count(小标签模式用)、key 等
|
|
|
+ tabList: {
|
|
|
+ type: Array,
|
|
|
+ required: true,
|
|
|
+ default: () => [],
|
|
|
+ },
|
|
|
+ // 模式:button(带数量按钮标签)、capsule(分段选项卡)
|
|
|
+ mode: {
|
|
|
+ type: String,
|
|
|
+ default: 'button ',
|
|
|
+ },
|
|
|
+ // v-model 绑定的选中值
|
|
|
+ activeKey: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: undefined,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ const currentActive = computed({
|
|
|
+ get() {
|
|
|
+ return props.activeKey;
|
|
|
+ },
|
|
|
+ set(value) {
|
|
|
+ emit('update:activeKey', value);
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ const emit = defineEmits(['update:activeKey']);
|
|
|
+
|
|
|
+ const handleTabClick = (key) => {
|
|
|
+ currentActive.value = key;
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+ .tab-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 小标签模式样式 */
|
|
|
+ .tab-group-small {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+ .tab-item-small {
|
|
|
+ padding: 3px 12px;
|
|
|
+ border: 1px solid #dcdcdc;
|
|
|
+ border-radius: 4px;
|
|
|
+ background-color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ .tab-item-small.active {
|
|
|
+ background-color: var(--vxe-ui-font-primary-color);
|
|
|
+ color: #fff;
|
|
|
+ border-color: var(--vxe-ui-font-primary-color);
|
|
|
+ }
|
|
|
+ .count-badge {
|
|
|
+ margin-left: 4px;
|
|
|
+ font-size: 0.9em;
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 大选项卡模式样式 */
|
|
|
+ .tab-group-large {
|
|
|
+ display: flex;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: #f3f3f3;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+ .tab-item-large {
|
|
|
+ text-align: center;
|
|
|
+ padding: 5px 25px;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #333;
|
|
|
+ background-color: transparent;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s ease;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ .tab-item-large.active {
|
|
|
+ background-color:var(--vxe-ui-font-primary-color);
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+</style>
|