返回目录
组件详情入口
导航
@vean/ui
SPageTabs

PageTabs

PageTabs 属于 导航 分类。建议先看演示与用法,再对照 API 表格完成接入和样式调整。

先用快捷跳转面板找到概述、用法、演示和 API,再往下细读完整文档内容。

快速跳转

同分类组件

如果你在同一类交互里做组合,这些组件通常会一起出现。

页面标签

概述

一个用于在不同页面或视图之间导航的标签页界面。它支持可关闭的标签、上下文菜单和可自定义的样式。

特性

  • 数据驱动的 Compact 组合 — SPageTabs 将整体结构委托给 Aria 的泛型 PageTabsCompact<T>,由它负责标签迭代、固定排序、关闭语义、上下文菜单接线以及默认标签体(图标 + 标签 + 固定 + 关闭 + 指示器)。
  • 受控/非受控状态 — modelValue / items 支持 v-model / v-model:items(受控);省略时通过 useControllableState 回退到内部状态。
  • 带异步守卫的可关闭标签 — 每个未固定的标签都渲染关闭按钮;beforeClose 可返回 false 或解析为 false 的 Promise 来阻止关闭。关闭当前标签会自动激活下一个(或上一个)兄弟标签;Backspace 键与中键点击(middleClickClose)关闭开箱即用。
  • 固定/取消固定与自动排序 — 固定标签在任何变更后自动排到最前(固定分组优先,然后是普通标签;hidePinnedIcon 仅控制显示,不影响排序);内联固定按钮切换固定状态,上下文菜单提供 固定 / 取消固定。
  • 拖拽调整顺序 — 启用 draggable 后,标签可横向拖拽改变位置。重排采用与浏览器标签栏(Chrome / VS Code)一致的分区限制:标签只能在自己所在分区内重排 —— 固定分组最前,然后是普通标签 —— 未固定标签拖到固定区边界时会实时停住,永远不会落到固定标签之前。条目显式设置 draggable: false 时该标签被锁定:自身不可拖拽,同时充当屏障,其他标签无法插入到它的位置(如锁定在最首位的主页标签)。拖拽由 Aria 的 useSortableList 驱动:被拖标签保留自身占位、只用 transform 跟随光标,其余标签通过 FLIP 平滑滑动让位;松手后应用新顺序(触发 update:items),被拖标签滑入最终位置。键盘同样可排序:聚焦标签后按 Space 拾起、方向键移动、Space / Enter 落下、Escape 取消。tabDragStart / tabDragMove / tabDragEnd 会发出实时的拖拽状态 { item, index }。
  • 上下文菜单工厂 — menuFactory(tab, state) 接收悬停标签与 PageTabsState(close、closeLeft、closeRight、closeOther、closeAll、pin、unpin 及其各自的 *Closable 布尔值)来构建自定义菜单;selectContextMenu 发出所选动作与标签。
  • 完整键盘支持 — useRovingFocusGroup 提供方向键移动;Enter 激活标签,Backspace 关闭标签,Space 拾起标签进入键盘排序。
  • 活动标签自动滚动 — usePageTabsScroll 使活动标签水平居中(平滑 scrollTo),并将垂直滚轮转换为水平滚动。
  • 三种视觉变体 — variant(chrome / card / slider)带各变体指示器(chrome 圆角 SVG / slider 下划线)与 size(xs…2xl),通过 pageTabsVariants 的 scv() 配方应用。
  • 六个自定义插槽 — item(scoped { item, index, active, closable })、icon、label、indicator、pin-icon、close-icon。
  • 本地化无障碍文案 — 关闭/固定按钮回退到本地化的 aria-label(closeTab / pinTab / unpinTab),内置 13 种语言;每个按钮可通过 aria-label 覆盖。
  • Aria 组合 — PageTabsRoot / PageTabsItem / PageTabsClose / PageTabsPin / PageTabsCompact 均可从 @vean/aria/page-tabs 导入,用于完全自定义样式构建。

用法

SPageTabs 将标签管理委托给 Aria 的 PageTabsCompact。如需无样式、数据驱动的组合,请从 @vean/aria/page-tabs 导入 PageTabsCompact。

演示

基础

Home
Profile
Manage
Doc
About

Draggable

Home
Manage
Profile
Doc
About

Drag tabs to reorder them within their own zone: pinned tabs reorder among themselves at the front, and unpinned tabs cannot be dragged past the pinned group — they halt at the boundary. The first tab sets draggable: false , so it is locked in place and no other tab can be dropped before it.

API

Aria 层

7

PageTabs<T>

21 属性6 插槽
属性
属性名类型默认值描述
class
ClassValue
—
根元素类
size
ThemeSize
—
组件的视觉尺寸。
variant
PageTabsVariant
—
该组件的视觉变体。
ui
Partial<PageTabsUi>
—
该组件的按槽类重写。
items
T[]
—
由该组件渲染的项。
menuFactory
((tab: T, state: PageTabsState) => PageTabsContextMenuOptionData[])
—
一个用于为每个标签页生成上下文菜单选项的工厂函数。
beforeClose
((value: string) => MaybePromise<boolean | void>)
—
在关闭标签页之前调用回调函数。返回 `false` 或一个解析结果为 `false` 的 Promise,以阻止关闭操作。
itemProps
BaseProps
—
该组件的按槽类重写。
pinProps
BaseProps
—
该组件的按槽类重写。
closeProps
BaseProps
—
该组件的按槽类重写。
contextMenuProps
Omit<ContextMenuCompactProps<import("@/index").DefinedValue>, 'options'>
—
上下文菜单组件的附加属性。
modelValue
string
—
当前选中的标签页值。
middleClickClose
boolean
—
中键单击标签页是否会关闭该标签页。
draggable
boolean
—
是否可以通过拖拽重新排列标签页。标签页仅可在 其所在区域内重新排列——固定组始终位于最前。带有显式 `draggable: false` 属性的标签页 项将被锁定在原位。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
currentTabStopId
string | null
—
当前停止项的受控值。可作为 `v-model` 进行绑定。
defaultCurrentTabStopId
string
—
当前停止项的值。 当不需要控制停止项的状态时使用。
preventScrollOnEntryFocus
boolean
—
当值为 `true` 时,将防止在获得焦点时滚动到焦点项。
插槽
插槽名参数描述
item
PageTabsCompactItemSlotProps<T>
默认标签页项正文的自定义内容。
icon
PageTabsCompactItemSlotProps<T>
标签图标的自定义内容。
label
PageTabsCompactItemSlotProps<T>
标签的自定义内容。
indicator
PageTabsCompactItemSlotProps<T>
标签指示器的自定义内容。
pin-icon
(() => void)
针对图钉图标的自定义内容。
close-icon
(() => void)
关闭图标的自定义内容。

PageTabsClose

4 属性
属性
属性名类型默认值描述
type
ButtonType
'button'
按钮元素的类型。可以是 'button'、'submit' 或 'reset' 之一。
disabled
boolean
—
该组件是否已禁用。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。

PageTabsCompact<T>

17 属性6 插槽
属性
属性名类型默认值描述
items
T[]
—
由该组件渲染的项。
menuFactory
((tab: T, state: PageTabsState) => PageTabsContextMenuOptionData[])
—
一个用于为每个标签页生成上下文菜单选项的工厂函数。
beforeClose
((value: string) => MaybePromise<boolean | void>)
—
在关闭标签页之前调用回调函数。返回 `false` 或一个解析结果为 `false` 的 Promise,以阻止关闭操作。
itemProps
BaseProps
—
该组件的按槽类重写。
pinProps
BaseProps
—
该组件的按槽类重写。
closeProps
BaseProps
—
该组件的按槽类重写。
contextMenuProps
Omit<ContextMenuCompactProps<import("@/index").DefinedValue>, 'options'>
—
上下文菜单组件的附加属性。
modelValue
string
—
当前选中的标签页值。
middleClickClose
boolean
—
中键单击标签页是否会关闭该标签页。
draggable
boolean
—
是否可以通过拖拽重新排列标签页。标签页仅可在 其所在区域内重新排列——固定组始终位于最前。带有显式 `draggable: false` 属性的标签页 项将被锁定在原位。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
currentTabStopId
string | null
—
当前停止项的受控值。可作为 `v-model` 进行绑定。
defaultCurrentTabStopId
string
—
当前停止项的值。 当不需要控制停止项的状态时使用。
preventScrollOnEntryFocus
boolean
—
当值为 `true` 时,将防止在获得焦点时滚动到焦点项。
插槽
插槽名参数描述
item
PageTabsCompactItemSlotProps<T>
默认标签页项正文的自定义内容。
icon
PageTabsCompactItemSlotProps<T>
标签图标的自定义内容。
label
PageTabsCompactItemSlotProps<T>
标签的自定义内容。
indicator
PageTabsCompactItemSlotProps<T>
标签指示器的自定义内容。
pin-icon
(() => void)
针对图钉图标的自定义内容。
close-icon
(() => void)
关闭图标的自定义内容。

PageTabsCompactItem

PageTabsItem

4 属性
属性
属性名类型默认值描述
value
string
—
制表符的独特价值。
pinned
boolean
—
该标签页是否已被固定。
draggable
boolean
—
此标签页是否启用了拖拽重新排序功能。不可拖拽的标签页会被 锁定在原位:既无法被拖拽,其他标签页也无法拖放 到其上。固定标签页仅可在固定区域内重新排序。
index
number
—
`items` 中的选项卡索引,用于构建拖拽有效载荷。

PageTabsPin

4 属性
属性
属性名类型默认值描述
type
ButtonType
'button'
按钮元素的类型。可以是 'button'、'submit' 或 'reset' 之一。
disabled
boolean
—
该组件是否已禁用。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。

PageTabsRoot

10 属性
属性
属性名类型默认值描述
modelValue
string
—
当前选中的标签页值。
middleClickClose
boolean
—
中键单击标签页是否会关闭该标签页。
draggable
boolean
—
是否可以通过拖拽重新排列标签页。标签页仅可在 其所在区域内重新排列——固定组始终位于最前。带有显式 `draggable: false` 属性的标签页 项将被锁定在原位。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
dir
Direction
—
项目之间的导航方向。
loop
boolean
false
键盘导航是否应循环往复
currentTabStopId
string | null
—
当前停止项的受控值。可作为 `v-model` 进行绑定。
defaultCurrentTabStopId
string
—
当前停止项的值。 当不需要控制停止项的状态时使用。
preventScrollOnEntryFocus
boolean
—
当值为 `true` 时,将防止在获得焦点时滚动到焦点项。

备注

架构与竞品对比

关注点VeanUIAnt Design TabsElement Plus Tabstags-view(vue-element-admin 风格)
Aria / 样式双层分离✅ @vean/aria/page-tabs + scv()❌ 单一包❌ 单一包❌ 各应用自研
数据驱动 Compact API✅ 泛型 PageTabsCompact<T> + items✅ 配置驱动(items)✅ 配置驱动✅ 各应用自研
受控/非受控✅ modelValue/items + useControllableState✅ activeKey / defaultActiveKey✅ v-model—
可关闭 + 异步守卫✅ beforeClose(false / Promise<false>)✅ onEdit + beforeChange✅ closable / before-leave✅ before-close
固定/取消固定 + 自动排序✅ 固定标签排到最前❌(仅自定义 tabLabel)❌✅(各应用,如 affix-tab)
拖拽调整顺序✅ draggable + tabDragStart/Move/End❌❌✅(各应用)
上下文菜单(左/右/其他/全部关闭)✅ menuFactory + PageTabsState❌(仅 more 的下拉菜单)❌✅(各应用)
中键点击关闭✅ middleClickClose❌❌✅(各应用)
键盘(roving focus + Enter/Backspace)✅ useRovingFocusGroup✅ 方向键 / Home / End✅ 方向键❌
活动标签自动滚动✅ 居中 scrollTo + 滚轮转横向✅ tabBar auto❌✅(各应用)
变体系统✅ chrome/card/slider × xs…2xl✅ line/card/editable-card✅ card/border-card—
本地化 aria-label✅ locale 注册表(13 种语言)部分支持——
插槽✅ 6 个类型化插槽✅ label/closeIcon/…✅ label/icon/…—

运行时注意事项

  1. 固定标签不可关闭 — closable 由 !pinned 推导;固定标签不渲染关闭按钮,中键 / Backspace / 上下文菜单关闭动作对其禁用。
  2. 关闭活动标签的回退 — 关闭活动标签时激活下一个兄弟标签,若为最后一个则回退到上一个;关闭最后一个标签时 modelValue 变为 ''(无活动标签)。
  3. 异步 beforeClose — 可为同步函数或返回 Promise;只有解析为 false 才会阻止关闭。close 事件在守卫通过且标签被移除后触发。
  4. 固定排序 — sortTabs 按 固定 → 普通 顺序稳定重排(保持各组内相对顺序),顺序变化时发出 update:items;受控模式下父组件需接受新顺序才能看到重排。
  5. 受控与非受控 — 提供了 modelValue / items prop 时,内部写入只发出 update:modelValue / update:items;DOM 跟随 prop,外部变更会自动重新渲染。
  6. 上下文菜单目标 — 悬停标签(pointerenter)会将其设为上下文目标并发出 contextmenu;菜单仅在 menuFactory 返回非空选项时渲染。
  7. 拖拽调整顺序的边界 — 拖拽重排是 PageTabsCompact 层面的特性(draggable)。排序按分区限制:标签只能在自己所在分区内重排(固定 → 普通;所有固定标签 —— 含 hidePinnedIcon —— 同属一个分区),因此未固定标签永远无法拖到固定标签之前 —— 实时重排在边界处被阻断,sortTabs 始终维护该分区不变量。条目显式设置 draggable: false 时被完全锁定:不可拖拽且不参与碰撞检测,其他标签无法落到它的位置。受控模式(v-model:items)下父组件需接受重排后的 update:items 才能看到新顺序。单独组合 PageTabsRoot / PageTabsItem 不支持拖拽。
  8. Locale 回退 — 关闭/固定按钮的 aria-label 来自 useLocaleMessages;缺失 key 回退到默认英文包;按钮上的显式 aria-label 优先。

FAQ

如何阻止关闭标签?

从 beforeClose 返回 false(或解析为 false 的 Promise)。该守卫适用于关闭按钮、中键点击、Backspace 与上下文菜单关闭动作。固定标签只需标记 pinned: true——固定标签永不可关闭。

为什么固定标签排在最前?

固定是为了让重要页面始终可达;sortTabs 将固定标签作为一组(含 hidePinnedIcon)移到普通标签之前,同时保持各组内的相对顺序。若以任意顺序传入 pinned 条目,组件会在挂载时重排并通过 update:items 发出排序后的数组。

能自定义上下文菜单吗?

可以——实现 menuFactory(tab, state)。state 暴露 close、closeLeft、closeRight、closeOther、closeAll、pin、unpin 及对应的 *Closable 标志,可禁用无关动作(如第一个标签上的"关闭左侧")。选择菜单项会执行其 action 并发出 selectContextMenu(menu, tab)。

如何优雅地关闭活动标签?

关闭活动标签会自动激活下一个兄弟标签(若关闭的是最后一个则激活上一个)。若关闭最后一个剩余标签,modelValue 变为 '',无标签处于活动状态。

支持哪些键盘快捷键?

方向键在标签间移动焦点(roving focus),Enter 激活聚焦的标签,Backspace 关闭它(除非固定或被 beforeClose 阻止)。开启 middleClickClose 时中键点击也可关闭。

能构建完全自定义的页面标签吗?

可以——从 @vean/aria/page-tabs 组合 PageTabsRoot / PageTabsItem / PageTabsClose / PageTabsPin / PageTabsCompact,并通过 providePageTabsUi(或 SPageTabs 的 ui prop)注入样式。item 插槽接收 { item, index, active, closable } scoped props 用于逐标签渲染。

如何启用拖拽调整顺序?

在 SPageTabs(或 PageTabsCompact)上设置 draggable。标签即可横向拖拽,带浮动预览与平滑滑动动画;新顺序通过 v-model:items 写回。与浏览器标签栏一致,重排按分区限制:固定标签(含 hidePinnedIcon)在最前方自行重排,未固定标签无法拖过固定区 —— 拖到边界时会实时停住。要锁定单个标签(如保持主页标签在最首位),在该条目上设置 draggable: false:它自身不可拖拽,其他标签也无法落到它的位置。

更新日志

版本记录按发布版本分组,便于快速查看这个组件在不同版本里的实际变更。

v0.50.0

2026-10-02

对比版本

重构

将 @dnd-kit 替换为 useSortableList

范围: page-tabs作者: soybeanjs查看提交932ff

样式

更新选中项的颜色,以提高可见性

范围: page-tabs作者: soybeanjs查看提交4a8ea

样式

调整布局并优化关闭按钮样式,以实现更好的对齐效果

范围: page-tabs作者: soybeanjs查看提交042cb

样式

调整布局并优化关闭按钮样式,以实现更好的对齐效果

范围: page-tabs作者: soybeanjs查看提交042cb

样式

更新选中项的颜色,以提高可见性

范围: page-tabs作者: soybeanjs查看提交4a8ea

重构

将 @dnd-kit 替换为 useSortableList

范围: page-tabs作者: soybeanjs查看提交932ff

v0.30.0

2026-08-20

对比版本

新功能

支持拖拽

范围: page-tabs作者: soybeanfe查看提交61d24

新功能

支持拖拽

范围: page-tabs作者: soybeanfe查看提交61d24

v0.19.0

2026-05-11

对比版本

新功能

实施 PageTabsCmpact

范围: page-tabs作者: soybeanfe查看提交93a56

v0.6.5

2026-02-08

对比版本

修复

从 forwardedProps 中省略 beforeClose prop

范围: page-tabs作者: soybeanjs查看提交37fba

v0.6.2

2026-02-08

对比版本

修复

修正滚动条 centerX 值

范围: page-tabs作者: soybeanjs查看提交1dadd

v0.6.1

2026-02-07

对比版本

修复

根据固定状态为标签页添加排序功能

范围: page-tabs作者: soybeanjs查看提交f5bac

v0.6.0

2026-02-07

对比版本

重构

简化上下文和状态管理,删除未使用的操作

范围: page-tabs作者: soybeanjs查看提交ded83

v0.4.3

2026-02-01

对比版本

修复

修复标签关闭功能

范围: page-tabs作者: soybeanjs查看提交ca73e

v0.4.2

2026-02-01

对比版本

优化

优化页面标签逻辑

范围: page-tabs作者: soybeanjs查看提交a2a1c

v0.4.1

2026-02-01

对比版本

重构

重构上下文和操作,改进标签管理

范围: page-tabs作者: soybeanjs查看提交2b884