TabList.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <div class="tabs-container" :class="[`tabs-type-${type}`, { 'tabs-small': tabs.length <= 2 }]">
  3. <div
  4. v-for="(tab, index) in tabs"
  5. :key="index"
  6. class="tab-item"
  7. :class="{ active: isActive(index, tab) }"
  8. @click="handleTabClick(index, tab)"
  9. >
  10. {{ getTabTitle(tab) }}
  11. </div>
  12. </div>
  13. </template>
  14. <script setup>
  15. const props = defineProps({
  16. tabs: {
  17. type: Array,
  18. required: true,
  19. default: () => []
  20. },
  21. modelValue: {
  22. type: [Number, String],
  23. default: 0
  24. },
  25. type: {
  26. type: String,
  27. default: 'default', // 'default' | 'light'
  28. validator: (value) => ['default', 'light'].includes(value)
  29. }
  30. });
  31. const emit = defineEmits(['update:modelValue', 'change']);
  32. // 判断是否为对象格式的 tab
  33. const isObjectTab = (tab) => {
  34. return typeof tab === 'object' && tab !== null && (tab.title !== undefined || tab.label !== undefined || tab.name !== undefined);
  35. };
  36. // 获取 tab 的标题
  37. const getTabTitle = (tab) => {
  38. if (isObjectTab(tab)) {
  39. return tab.title || tab.label || tab.name || '';
  40. }
  41. return tab;
  42. };
  43. // 判断当前 tab 是否激活
  44. const isActive = (index, tab) => {
  45. if (isObjectTab(tab)) {
  46. // 对象格式:比较 value
  47. if(tab.value){
  48. return props.modelValue === tab.value;
  49. }else{
  50. return props.modelValue === tab.id;
  51. }
  52. }
  53. // 字符串/简单格式:比较索引
  54. return props.modelValue === index;
  55. };
  56. const handleTabClick = (index, tab) => {
  57. if (isObjectTab(tab)) {
  58. // 对象格式:传递 value
  59. emit('update:modelValue', tab.value);
  60. emit('change', tab.value || tab.id, tab, index);
  61. } else {
  62. // 字符串/简单格式:传递索引
  63. emit('update:modelValue', index);
  64. emit('change', index, tab);
  65. }
  66. };
  67. </script>
  68. <style scoped lang="scss">
  69. .tabs-container {
  70. display: flex;
  71. align-items: center;
  72. gap: 8px;
  73. .tab-item {
  74. border-radius: 20px;
  75. text-align: center;
  76. }
  77. // 标签数量 <= 2 时的样式
  78. &.tabs-small {
  79. gap: 8px;
  80. .tab-item {
  81. padding: 5px 12px;
  82. }
  83. }
  84. // 默认样式
  85. &.tabs-type-default {
  86. justify-content: center;
  87. background: #fff;
  88. padding: 5px 0;
  89. .tab-item {
  90. padding: 4px 12px;
  91. color: rgba(0, 0, 0, 0.5);
  92. border: 1px solid transparent;
  93. &.active {
  94. background: rgba(33, 153, 248, 0.1);
  95. color: #2199F8;
  96. border: 1px solid #2199F8;
  97. }
  98. }
  99. }
  100. // 浅色样式(激活:浅蓝色背景+深蓝色文字,未激活:浅灰色背景+中灰色文字)
  101. &.tabs-type-light {
  102. .tab-item {
  103. background: #F7F8FA;
  104. color: #8B8B8B;
  105. &.active {
  106. background: rgba(33, 153, 248, 0.1);
  107. color: #2199F8;
  108. }
  109. }
  110. }
  111. }
  112. </style>