Вкладки
Переключение содержимого одного уровня. Строго следует шаблону вкладок WAI-ARIA APG: три связанные роли 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="Золото">Точечная роспись gamboge.</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="Золото">Точечная роспись gamboge.</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: 'Свиток 1', content: 'Содержимое первого свитка.', disabled: false },
{ name: 's2', label: 'Свиток 2', 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: 'Свиток 1', content: 'Содержимое первого свитка.', disabled: false },
{ name: 's2', label: 'Свиток 2', 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 | Имя активной вкладки (v-model) | string | — |
| type | Внешний вид | "line" | "card" | 'line' |
| closable | Можно ли закрывать вкладки | boolean | false |
| addable | Показывать ли кнопку добавления | boolean | false |
| tabPosition | Положение вкладок | "top" | "bottom" | 'top' |
| sx | Свойство sx для быстрой вёрстки | LhSxProps | — |
LhTabs События
| Событие | Описание | Параметры обратного вызова |
|---|---|---|
| update:modelValue | Изменение активной вкладки (v-model) | (name: string) |
| tab-change | Изменение активной вкладки | (name: string) |
| tab-remove | Закрытие вкладки | (name: string) |
| tab-add | Клик по кнопке добавления | — |
LhTabPane Props
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
| name | Уникальный идентификатор вкладки (стабильный ключ; динамически изменять не рекомендуется) | string | — |
| label | Заголовок вкладки | string | '' |
| disabled | Отключить вкладку | boolean | false |
Слоты
| Слот | Описание | Компонент |
|---|---|---|
| default | Панели вкладок (список LhTabPane) | LhTabs |
| default | Содержимое панели | LhTabPane |
Доступность
Строго следует шаблону вкладок WAI-ARIA APG:
- Заголовки вкладок имеют
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 {
/** Имя активной вкладки (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'