20260824172723
This commit is contained in:
1 parent
791d1e01d7
commit
97aea665f9
10 files changed
+443
-723
No files matched your search
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import { computed, Fragment, isVNode, nextTick, reactive, ref, useId, useSlots, watch } from 'vue'
|
||||
import Scrollbar from '@/components/ui/scrollbar/scrollbar.vue'
|
||||
|
||||
/* ---------- props / emits / slots ---------- */
|
||||
const props = defineProps({
|
||||
@@ -11,6 +12,14 @@ const props = defineProps({
|
||||
default: 'top',
|
||||
validator: (value) => ['top', 'left', 'right'].includes(value),
|
||||
},
|
||||
/** 样式类型:line 下划线指示条,pill 胶囊式标签 */
|
||||
type: {
|
||||
type: String,
|
||||
default: 'line',
|
||||
validator: (value) => ['line', 'pill'].includes(value),
|
||||
},
|
||||
/** 仅渲染标签栏(不渲染内容区):用于纯导航场景,内容由外部 v-show 控制 */
|
||||
navOnly: { type: Boolean, default: false },
|
||||
/** 标签列表在标签栏内居中显示(top 水平居中,left/right 垂直居中) */
|
||||
centered: { type: Boolean, default: false },
|
||||
/** 整组禁用 */
|
||||
@@ -230,46 +239,52 @@ function onTablistKeydown(event) {
|
||||
<template>
|
||||
<div
|
||||
class="tabs"
|
||||
:class="[`tabs-${placement}`, { 'tabs-disabled': disabled, 'tabs-centered': centered }]"
|
||||
:class="[
|
||||
`tabs-${placement}`,
|
||||
`tabs-${type}`,
|
||||
{ 'tabs-disabled': disabled, 'tabs-centered': centered, 'tabs-nav-only': navOnly },
|
||||
]"
|
||||
>
|
||||
<div class="tabs-nav">
|
||||
<div v-if="slots.leftExtra" class="tabs-nav-extra">
|
||||
<slot name="leftExtra" />
|
||||
</div>
|
||||
<div
|
||||
class="tabs-nav-list"
|
||||
role="tablist"
|
||||
:aria-orientation="placement === 'top' ? 'horizontal' : 'vertical'"
|
||||
@keydown="onTablistKeydown"
|
||||
>
|
||||
<button
|
||||
v-for="(pane, index) in mergedPanes"
|
||||
:key="pane.key"
|
||||
:ref="(el) => setTabRef(pane.key, el)"
|
||||
type="button"
|
||||
class="tabs-tab"
|
||||
:class="{
|
||||
'tabs-tab-active': currentKey === pane.key,
|
||||
'tabs-tab-disabled': pane.disabled,
|
||||
}"
|
||||
role="tab"
|
||||
:id="`${baseId}-tab-${index}`"
|
||||
:aria-selected="currentKey === pane.key"
|
||||
:aria-controls="`${baseId}-panel-${index}`"
|
||||
:tabindex="currentKey === pane.key ? 0 : -1"
|
||||
:disabled="disabled || pane.disabled"
|
||||
@click="(event) => onTabClick(pane, event)"
|
||||
<Scrollbar class="tabs-nav-scroll">
|
||||
<div
|
||||
class="tabs-nav-list"
|
||||
role="tablist"
|
||||
:aria-orientation="placement === 'top' ? 'horizontal' : 'vertical'"
|
||||
@keydown="onTablistKeydown"
|
||||
>
|
||||
<component :is="pane.labelRender" v-if="pane.labelRender" />
|
||||
<span v-else-if="pane.labelText !== undefined">{{ pane.labelText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
v-for="(pane, index) in mergedPanes"
|
||||
:key="pane.key"
|
||||
:ref="(el) => setTabRef(pane.key, el)"
|
||||
type="button"
|
||||
class="tabs-tab"
|
||||
:class="{
|
||||
'tabs-tab-active': currentKey === pane.key,
|
||||
'tabs-tab-disabled': pane.disabled,
|
||||
}"
|
||||
role="tab"
|
||||
:id="`${baseId}-tab-${index}`"
|
||||
:aria-selected="currentKey === pane.key"
|
||||
:aria-controls="`${baseId}-panel-${index}`"
|
||||
:tabindex="currentKey === pane.key ? 0 : -1"
|
||||
:disabled="disabled || pane.disabled"
|
||||
@click="(event) => onTabClick(pane, event)"
|
||||
>
|
||||
<component :is="pane.labelRender" v-if="pane.labelRender" />
|
||||
<span v-else-if="pane.labelText !== undefined">{{ pane.labelText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</Scrollbar>
|
||||
<div v-if="slots.rightExtra" class="tabs-nav-extra">
|
||||
<slot name="rightExtra" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs-content">
|
||||
<div v-if="!navOnly" class="tabs-content">
|
||||
<template v-for="(pane, index) in mergedPanes" :key="pane.key">
|
||||
<div
|
||||
v-if="renderedKeys.has(pane.key)"
|
||||
|
||||
Reference in new issue
Block a user