Skip to content
API 风格:

Tabs 分頁 ​

同層內容切換。嚴格對齊 WAI-ARIA APG tabs pattern:tablist/tab/tabpanel 三角色關聯 + roving tabindex + 方向鍵導覽。

基礎用法 ​

基礎用法
水墨散文內容。
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs>
    <LhTabPane name="prose" label="散文">水墨散文内容。</LhTabPane>
    <LhTabPane name="poem" label="诗词">诗词格律内容。</LhTabPane>
    <LhTabPane name="calligraphy" label="书法">书法碑帖内容。</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs>
    <LhTabPane name="prose" label="散文">水墨散文内容。</LhTabPane>
    <LhTabPane name="poem" label="诗词">诗词格律内容。</LhTabPane>
    <LhTabPane name="calligraphy" label="书法">书法碑帖内容。</LhTabPane>
  </LhTabs>
</template>

卡片外觀與停用 ​

卡片外觀與停用
墨分五色。
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs type="card">
    <LhTabPane name="ink" label="墨">墨分五色。</LhTabPane>
    <LhTabPane name="cinnabar" label="朱" disabled>丹砂不可用。</LhTabPane>
    <LhTabPane name="gold" label="金">藤黄点染。</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs type="card">
    <LhTabPane name="ink" label="墨">墨分五色。</LhTabPane>
    <LhTabPane name="cinnabar" label="朱" disabled>丹砂不可用。</LhTabPane>
    <LhTabPane name="gold" label="金">藤黄点染。</LhTabPane>
  </LhTabs>
</template>

底部位置 ​

底部位置
山勢渾厚。
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs tab-position="bottom">
    <LhTabPane name="mountain" label="山">山势浑厚。</LhTabPane>
    <LhTabPane name="water" label="水">水意空灵。</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs tab-position="bottom">
    <LhTabPane name="mountain" label="山">山势浑厚。</LhTabPane>
    <LhTabPane name="water" label="水">水意空灵。</LhTabPane>
  </LhTabs>
</template>

可關閉與可新增 ​

可關閉與可新增
第一卷內容。
vue
<script setup lang="ts">
import { ref } from 'vue'
const panes = ref([
  { name: 's1', label: '画卷一', content: '第一卷内容。', disabled: false },
  { name: 's2', label: '画卷二', content: '第二卷内容。', disabled: false },
])
let index = 2

const removePane = (name) => {
  const target = panes.value.find((pane) => pane.name === name)
  if (target) panes.value.splice(panes.value.indexOf(target), 1)
}
const addPane = () => {
  index += 1
  panes.value.push({ name: `s${index}`, label: `画卷${index}`, content: '新卷内容。', disabled: false })
}
</script>

<template>
  <!-- 可關閉與可新增 -->
  <LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
    <LhTabPane
      v-for="pane in panes"
      :key="pane.name"
      :name="pane.name"
      :label="pane.label"
      :disabled="pane.disabled"
    >{{ pane.content }}</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {
  data() {
    return {
      panes: [
        { name: 's1', label: '画卷一', content: '第一卷内容。', disabled: false },
        { name: 's2', label: '画卷二', content: '第二卷内容。', disabled: false },
      ],
      index: 2,
    }
  },
  methods: {
    removePane(name) {
      const target = this.panes.find((pane) => pane.name === name)
      if (target) this.panes.splice(this.panes.indexOf(target), 1)
    },
    addPane() {
      this.index += 1
      this.panes.push({ name: `s${this.index}`, label: `画卷${this.index}`, content: '新卷内容。', disabled: false })
    },
  },
}
</script>

<template>
  <!-- 可關閉與可新增 -->
  <LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
    <LhTabPane
      v-for="pane in panes"
      :key="pane.name"
      :name="pane.name"
      :label="pane.label"
      :disabled="pane.disabled"
    >{{ pane.content }}</LhTabPane>
  </LhTabs>
</template>

關閉啟用分頁時元件會連動切換到相鄰可用分頁,並發出 tab-remove;由使用方負責從資料來源移除對應 pane。

受控用法 ​

受控用法
水墨內容。

當前分頁:mo

vue
<script setup lang="ts">
import { ref } from 'vue'
const active = ref('mo')
</script>

<template>
  <LhTabs v-model="active" type="card">
    <LhTabPane name="zh" label="国风">国风内容。</LhTabPane>
    <LhTabPane name="mo" label="水墨">水墨内容。</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {
  data() {
    return { active: 'mo' }
  },
}
</script>

<template>
  <LhTabs v-model="active" type="card">
    <LhTabPane name="zh" label="国风">国风内容。</LhTabPane>
    <LhTabPane name="mo" label="水墨">水墨内容。</LhTabPane>
  </LhTabs>
</template>

Tabs API ​

LhTabs Props ​

屬性名說明類型預設值
modelValue當前啟用分頁的 name(v-model)string—
type外觀"line" | "card"'line'
closable分頁是否可關閉booleanfalse
addable是否顯示新增按鈕booleanfalse
tabPosition分頁位置"top" | "bottom"'top'
sxsx 快速版面配置屬性LhSxProps—

LhTabs Events ​

事件名說明回呼參數
update:modelValue啟用分頁變化(v-model)(name: string)
tab-change啟用分頁變化(name: string)
tab-remove分頁關閉(name: string)
tab-add點選新增按鈕—

LhTabPane Props ​

屬性名說明類型預設值
name分頁唯一標識(穩定鍵,不建議動態修改)string—
label分頁標題string''
disabled是否停用booleanfalse

Slots ​

插槽名說明作用元件
default分頁面板(LhTabPane 列表)LhTabs
default面板內容LhTabPane

無障礙 ​

嚴格對齊 WAI-ARIA APG tabs pattern:

  • 分頁頭為 role="tablist",每個分頁為 role="tab"(aria-selected + aria-controls),面板為 role="tabpanel"(aria-labelledby + tabindex="0")
  • roving tabindex:僅啟用分頁可 Tab 聚焦,其餘為 tabindex="-1"
  • 方向鍵在可用分頁間移動並自動啟用(跳過停用項),Home/End 跳到首尾
  • closable 時按 Delete 鍵關閉當前分頁;關閉圖示為 aria-hidden 裝飾,鍵盤走 Delete,避免按鈕巢狀按鈕
  • 停用分頁不可聚焦啟用,tab-remove 等操作對停用項無效

類型定義 ​

本元件對外匯出的 TypeScript 類型結構如下(自動提取自 packages/components/tabs/src/types.ts 與 @lh-ui/share/core/* 原始碼,點選各條目展開檢視完整定義;屬性說明見上方 Props 表):

LhTabsProps
ts
export interface LhTabsProps {
  /** 當前啟用分頁的 name(v-model) */
  modelValue?: string
  /** 外觀 */
  type?: LhTabsType
  /** 分頁是否可關閉 */
  closable?: boolean
  /** 是否顯示新增按鈕 */
  addable?: boolean
  /** 分頁位置 */
  tabPosition?: LhTabsPosition
  /** sx 快速版面配置屬性 */
  sx?: LhSxProps
}
LhTabPaneProps
ts
export interface LhTabPaneProps {
  /** 分頁唯一標識(作為穩定鍵,不建議動態修改) */
  name: string
  /** 分頁標題 */
  label?: string
  /** 是否停用 */
  disabled?: boolean
}
LhTabsType (來自 @lh-ui/share/core/tabs)
ts
/**
 * 分頁外觀
 */
export type LhTabsType = 'line' | 'card'
LhTabsPosition (來自 @lh-ui/share/core/tabs)
ts
/**
 * 分頁位置
 */
export type LhTabsPosition = 'top' | 'bottom'