
Element Plus Tabs 组件完全指南从基础用法到可编辑标签页的实战解析【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus本文围绕 Element PlusVue 3 UI 组件库中 Tabs 标签页组件的官方文档展开完整覆盖基础用法、卡片样式、标签位置、自定义标签、可增删标签页、默认选中值以及完整的 API 参考并结合仓库源码packages/components/tabs与官方示例docs/examples/tabs深入讲解其底层实现原理。读完本文你将能够熟练运用 Tabs 组件搭建符合业务需求的标签页导航掌握v-model受控切换、动态增删标签页、懒渲染、切换拦截等进阶能力。快速上手最基础的标签页用法Tabs 用于把彼此相关、但属于不同类型的数据集合分隔展示是后台管理系统中最常见的导航形态之一。它的基础用法非常简洁使用el-tabs作为容器内部嵌套若干个el-tab-pane作为标签页通过v-model绑定当前激活标签页的name。官方基础示例docs/examples/tabs/basic.vue展示了最典型的写法template el-tabs v-modelactiveName classdemo-tabs tab-clickhandleClick el-tab-pane labelUser namefirstUser/el-tab-pane el-tab-pane labelConfig namesecondConfig/el-tab-pane el-tab-pane labelRole namethirdRole/el-tab-pane el-tab-pane labelTask namefourthTask/el-tab-pane /el-tabs /template script langts setup import { ref } from vue import type { TabsPaneContext } from element-plus const activeName ref(first) const handleClick (tab: TabsPaneContext, event: Event) { console.log(tab, event) } /script关键点说明默认激活默认情况下第一个 tab 处于激活状态。官方文档明确指出By default the first tab is selected as active。v-model绑定v-model绑定的值必须是某个el-tab-pane的name。如果某个el-tab-pane未显式指定name则默认使用其在兄弟节点中的序号从0开始作为标识例如第一个el-tab-pane的默认name就是0。这一点在 Tab-pane Attributes 中有明确说明也体现在源码 tab-pane.vue 中index由父级维护paneName计算逻辑为props.name ?? index.value。tab-click事件点击标签时触发回调参数为(pane: TabsPaneContext, ev: Event)。其中TabsPaneContext类型定义在 constants.ts包含了当前 pane 的uid、props、paneName、active等上下文信息。从源码结构看tabs.tsxTabs 组件整体由三个子部件协作完成TabNav标签导航条、TabBar激活指示条与TabPane内容面板它们分别对应 tab-nav.tsx、tab-bar.vue 与 tab-pane.vue。父组件通过provide注入tabsRootContextKey建立上下文el-tab-pane在挂载时调用registerPane注册自己激活状态由tabsRoot.currentName统一驱动。三种内置样式基础、卡片与边框卡片Tabs 通过type属性控制视觉形态取值如下type取值说明默认基础下划线样式标签下方有一条激活指示条card卡片样式每个标签是一个独立的卡片块border-card边框卡片样式整个标签区域带边框并呈卡片容器外观卡片样式Card Style设置typecard即可得到卡片样式的标签页docs/examples/tabs/card-style.vuetemplate el-tabs v-modelactiveName typecard classdemo-tabs tab-clickhandleClick el-tab-pane labelUser namefirstUser/el-tab-pane el-tab-pane labelConfig namesecondConfig/el-tab-pane el-tab-pane labelRole namethirdRole/el-tab-pane el-tab-pane labelTask namefourthTask/el-tab-pane /el-tabs /template边框卡片样式Border Card设置typeborder-carddocs/examples/tabs/border-card.vuetemplate el-tabs typeborder-card el-tab-pane labelUserUser/el-tab-pane el-tab-pane labelConfigConfig/el-tab-pane el-tab-pane labelRoleRole/el-tab-pane el-tab-pane labelTaskTask/el-tab-pane /el-tabs /template注意此示例中没有显式指定name所有 pane 使用默认序号作为名称因此这里也没有绑定v-model。type在源码 tabs.tsx 中被定义为 | card | border-card枚举默认值为。此外还有一个可增删标签页的隐含前提官方文档明确指出 Only card type Tabs support addable closeable即只有typecard的 Tabs 才支持添加与关闭标签页的能力下文会详细展开。控制标签位置top / right / bottom / lefttab-position属性用于设置标签条的位置官方文档给出的可选值即tabPositionleft|right|top|bottom默认是top。结合el-radio-group可以实时切换四种方位docs/examples/tabs/tab-position.vuetemplate el-radio-group v-modeltabPosition stylemargin-bottom: 30px el-radio-button valuetoptop/el-radio-button el-radio-button valuerightright/el-radio-button el-radio-button valuebottombottom/el-radio-button el-radio-button valueleftleft/el-radio-button /el-radio-group el-tabs :tab-positiontabPosition styleheight: 200px classdemo-tabs el-tab-pane labelUserUser/el-tab-pane el-tab-pane labelConfigConfig/el-tab-pane el-tab-pane labelRoleRole/el-tab-pane el-tab-pane labelTaskTask/el-tab-pane /el-tabs /template script langts setup import { ref } from vue import type { TabsInstance } from element-plus const tabPosition refTabsInstance[tabPosition](left) /script两个实战细节容器高度当标签位于left或right时建议给el-tabs设置一个明确的高度示例中为200px否则内容区高度无法自适应撑开。示例还补充了样式.el-tabs--right .el-tabs__content, .el-tabs--left .el-tabs__content { height: 100%; }类型安全官方示例通过TabsInstance[tabPosition]获取tabPosition的联合类型避免手写字符串拼错。在源码层面tab-position会生成形如el-tabs--left、el-tabs--right的修饰类通过useNamespace的is()方法主题样式 theme-chalk 中对应处理了不同方位下导航条与内容区的布局关系。自定义标签内容named slot 进阶用法默认情况下标签标题由el-tab-pane的label属性决定。当需要更丰富的标签展示如带图标、徽标或自定义排版时可以使用el-tab-pane暴露的#label具名插槽完全接管标签内容。官方示例docs/examples/tabs/custom-tab.vue在标签中同时渲染了一个日历图标和文字template el-tabs typeborder-card classdemo-tabs el-tab-pane template #label span classcustom-tabs-label el-iconcalendar //el-icon spanRoute/span /span /template Route /el-tab-pane el-tab-pane labelConfigConfig/el-tab-pane el-tab-pane labelRoleRole/el-tab-pane el-tab-pane labelTaskTask/el-tab-pane /el-tabs /template script langts setup import { Calendar } from element-plus/icons-vue /script使用要点插槽名为label声明于 Tab-pane Slots#label用于自定义 Tab-pane 的标签标题同时label属性仍可用作不自定义插槽时的标题文本。图标需要配合el-icon组件使用图标来源为element-plus/icons-vue包。示例中还通过custom-tabs-label类名调整了图标与文字的对齐方式vertical-align: middle与间距margin-left: 4px保证视觉居中。从源码看tab-pane.vue当slots.label存在时组件在每次更新前会调用tabsRoot.nav$.value?.scheduleRender()通知导航条重新渲染确保自定义标签内容变更能即时反映到标签条上。可增删标签页editable / addable / closable 与 edit 事件官方文档明确指出只有卡片类型typecard的 Tabs 支持添加与关闭。相关能力由三个属性开启属性作用默认值closable每个标签页显示关闭按钮falseaddable显示添加标签按钮falseeditable同时开启添加 关闭等价于addable与closable的组合false在 tabs.tsx 中editable、addable、closable均被定义为布尔类型并且渲染逻辑为props.editable || props.addable时显示添加按钮、props.editable || props.closable时每个标签显示关闭按钮。另外el-tab-pane自身也支持closable属性且其最终取值遵循面板自身优先、回退到父级的合并策略见 tab-pane.vueprops.closable ?? tabsRoot.props.closable因此你可以全局开启、再单独对某个 pane 关闭。用 edit 统一处理增删官方动态标签示例docs/examples/tabs/dynamic-tabs.vue是后台可关闭多标签页的经典实现template el-tabs v-modeleditableTabsValue typecard editable classdemo-tabs edithandleTabsEdit el-tab-pane v-foritem in editableTabs :keyitem.name :labelitem.title :nameitem.name {{ item.content }} /el-tab-pane /el-tabs /template script langts setup import { ref } from vue import type { TabPaneName } from element-plus let tabIndex 2 const editableTabsValue ref(2) const editableTabs ref([ { title: Tab 1, name: 1, content: Tab 1 content, }, { title: Tab 2, name: 2, content: Tab 2 content, }, ]) const handleTabsEdit ( targetName: TabPaneName | undefined, action: remove | add ) { if (action add) { const newTabName ${tabIndex} editableTabs.value.push({ title: New Tab, name: newTabName, content: New Tab content, }) editableTabsValue.value newTabName } else if (action remove) { const tabs editableTabs.value let activeName editableTabsValue.value if (activeName targetName) { tabs.forEach((tab, index) { if (tab.name targetName) { const nextTab tabs[index 1] || tabs[index - 1] if (nextTab) { activeName nextTab.name } } }) } editableTabsValue.value activeName editableTabs.value tabs.filter((tab) tab.name ! targetName) } } /script这段代码揭示了 Tabs 的受控controlled使用模式组件本身只负责发出添加/删除的信号edit事件而标签页数据的新增、删除、激活态迁移完全由业务代码决定。这正是 Vue 生态中v-model 派生事件的典型双向绑定思路。只关闭不添加closable tab-remove如果只需要关闭能力可以不使用editable而是单独设置closable并监听tab-removedocs/examples/tabs/customized-trigger.vueel-tabs v-modeleditableTabsValue typecard classdemo-tabs closable tab-removeremoveTab !-- v-for 渲染 editableTabs -- /el-tabstab-remove事件携带被关闭 pane 的nameTabPaneName类型。关闭激活中的标签时需要自行决定激活态迁移到哪个邻居——官方示例采用的是优先下一个、否则上一个的策略const nextTab tabs[index 1] || tabs[index - 1]。自定义添加按钮图标从 2.4.0 版本起Tabs 新增了add-icon具名插槽用于自定义添加按钮的图标同版本还提供了addIcon插槽但已在文档中标记为deprecated废弃从 2.5.4 版本起统一推荐使用连字符风格的add-icon。官方示例docs/examples/tabs/customized-add-button-icon.vuetemplate el-tabs v-modeleditableTabsValue typecard classdemo-tabs editable edithandleTabsEdit template #add-icon el-iconSelect //el-icon /template !-- v-for 渲染 editableTabs -- /el-tabs /template script langts setup import { Select } from element-plus/icons-vue /script用外部按钮触发添加自定义触发按钮官方还提供了由页面上的普通按钮来触发新增标签的方案docs/examples/tabs/customized-trigger.vue不需要 Tabs 自带的图标而是自行维护数据源点击el-button时调用addTab向数组 push 一个新 pane 并同步更新v-modelel-button sizesmall clickaddTab(editableTabsValue)add tab/el-button el-tabs v-modeleditableTabsValue typecard closable tab-removeremoveTab !-- v-for 渲染 editableTabs -- /el-tabsconst addTab (targetName: string) { const newTabName ${tabIndex} editableTabs.value.push({ title: New Tab, name: newTabName, content: New Tab content, }) editableTabsValue.value newTabName }这再次印证了 Tabs 的增删属于信号由组件发、数据由业务管的受控模式。默认激活值与切换拦截default-value 与 before-leavedefault-value避免首帧切换动画2.11.9从 2.11.9 版本起Tabs 新增了default-value属性用于指定首次渲染时应当激活的标签的取值。它与v-model的区别在于v-model是受控值而default-value只在初始渲染时生效一次官方文档对其描述是 avoid initial transition——即在v-model尚未确定如异步获取时先按default-value渲染指定标签避免初始阶段发生一次标签切换过渡动画。官方示例docs/examples/tabs/default-value.vuetemplate el-tabs v-modelactiveName classdemo-tabs default-valuethird tab-clickhandleClick el-tab-pane v-fortab in tabs :keytab.name :labeltab.label :nametab.name default-value: third br / active: {{ activeName }} /el-tab-pane /el-tabs /template script langts setup import { ref } from vue const tabs ref([ { label: User, name: first }, { label: Config, name: second }, { label: Role, name: third }, { label: Task, name: fourth }, ]) const activeName ref() /script可以看到activeName初始为undefined而页面渲染时激活的是default-valuethird对应的Role标签。若未提供default-value组件则会回退到第一个标签作为默认激活项的行为。before-leave切换前的拦截钩子before-leave是切换标签前的钩子函数签名如下type BeforeLeaveHook ( activeName: TabPaneName, oldActiveName: TabPaneName ) Awaitablevoid | boolean拦截规则官方文档原话如果返回false或者返回一个被reject的Promise则本次切换被阻止。默认值为() true即不拦截。典型场景包括表单未保存时阻止切换、异步校验通过后才允许切换等el-tabs v-modelactiveName :before-leavebeforeLeave el-tab-pane labelForm nameform.../el-tab-pane el-tab-pane labelPreview namepreview.../el-tab-pane /el-tabsconst beforeLeave async (newName: TabPaneName) { if (newName preview !isFormValid.value) { await ElMessageBox.confirm(当前表单尚未保存确定离开吗) .then(() true) .catch(() false) } return true }从源码结构看切换流程由tabs.tsx中的setCurrentName触发先执行before-leave校验通过后再更新currentName并派发tab-change事件校验失败则保持原激活标签不变。让标签填满容器stretch 属性stretch属性用于控制标签是否自动拉伸以铺满容器宽度默认false。当设置为true时所有标签均分容器宽度适合标签数量固定且希望占满整行的布局如顶部一级导航。注意该属性在标签条位于left/right等垂直方向时通常不生效其设计初衷是水平铺满。无障碍与键盘焦点tabindex 属性从 2.11.7 版本起Tabs 新增了tabindex属性用于控制标签导航条上按钮的键盘 Tab 焦点顺序类型为string | number默认值为0。在 tabs.tsx 中该值被透传给内部TabNav并结合方向键切换实现完整的方向键导航与焦点管理提升键盘用户的可用性。Tabs API 全参考以下 API 完整整理自官方文档 docs/en-US/component/tabs.md字段、类型与默认值均以文档为准。Tabs Attributes名称说明类型默认值model-value/v-model绑定值即当前选中标签的name默认值为第一个标签的namestring/number—default-value^(2.11.9)首次渲染时应激活的标签值避免初始切换动画string/number—type标签类型 \| card \| border-cardclosable标签是否可关闭booleanfalseaddable标签是否可添加booleanfalseeditable标签是否可添加且可关闭booleanfalsetab-position标签条位置top \| right \| bottom \| lefttopstretch标签宽度是否自动撑满容器booleanfalsebefore-leave切换前的钩子函数返回false或返回被 reject 的Promise时阻止切换(activeName: TabPaneName, oldActiveName: TabPaneName) Awaitablevoid \| boolean() truetabindex^(2.11.7)标签导航条的 tabindexstring/number0Tabs Events名称说明参数tab-click点击标签时触发(pane: TabsPaneContext, ev: Event) voidtab-changeactiveName改变时触发(name: TabPaneName) voidtab-remove点击关闭按钮时触发(name: TabPaneName) voidtab-add点击添加按钮时触发() voidedit点击添加或关闭按钮时触发(paneName: TabPaneName \| undefined, action: remove \| add) voidTabs Slots名称说明子标签default自定义默认内容Tab-paneadd-icon^(2.5.4)自定义添加按钮图标—addIcon^(2.4.0) ^(deprecated)自定义添加按钮图标已废弃改用add-icon—Tabs Exposes名称说明类型currentName当前激活 pane 的名称RefTabPaneNametabNavRef^(2.9.10)TabNav 组件实例RefTabNavInstance \| undefinedTab-nav Exposes名称说明类型scrollToActiveTab滚动到当前激活标签() PromisevoidremoveFocus移除焦点状态() booleantabListRef^(2.9.10)el-tabs__navHTML 元素引用RefHTMLDivElement \| undefinedtabBarRef^(2.9.10)TabBar 实例引用RefTabBarInstance \| undefinedTab-bar Exposes名称说明类型ref^(2.9.10)标签根 HTML 元素RefHTMLDivElement \| undefinedupdate^(2.9.10)手动更新标签条样式返回更新后的样式() CSSPropertiesTab-pane Attributes名称说明类型默认值label标签标题stringdisabled标签是否禁用booleanfalsename对应 Tabs 的name标识即 pane 的别名默认是其在序列中的序号如第一个 pane 为0string/number—closable标签是否可关闭优先于 Tabs 上的closablebooleanfalselazy标签内容是否懒渲染booleanfalseTab-pane Slots名称说明defaultTab-pane 的内容labelTab-pane 的标签标题深入源码Tabs 的工作机制组件三件套TabNav、TabBar、TabPane从源码目录 packages/components/tabs/src 可以清晰看到 Tabs 的分层设计tabs.tsx顶层容器负责状态管理与协调tab-nav.tsx渲染标签导航条包含滚动、键盘导航、添加/关闭按钮tab-bar.vue渲染当前激活标签下方的滑动指示条并在update中计算其transform偏移tab-pane.vue渲染单个内容面板tab-pane.ts / tab-bar.ts定义对应的props类型constants.ts定义TabPaneName、TabsPaneContext、TabsRootContext等共享类型与tabsRootContextKey注入键composables/use-tab-nav-touch.ts移动端触摸滚动支持。状态流注册、激活与懒渲染el-tab-pane挂载时调用tabsRoot.registerPane(pane)注册自身tab-pane.vue卸载时调用unregisterPane注销同文件 L86-L88。激活判定为核心逻辑const active computed( () tabsRoot.currentName.value (props.name ?? index.value) ) const loaded ref(active.value) const shouldBeRender computed( () !props.lazy || loaded.value || active.value )这解释了lazy属性的底层实现当lazy为true时面板只有在被激活过loaded变为true之后才会真正渲染 DOMv-if由shouldBeRender控制此后即使切走也保持已挂载状态而默认情况下所有面板从一开始就渲染仅通过v-show控制显隐。这种先渲染后显隐 / 按需首渲染的区别直接影响大数据量面板的初始性能。事件与edit的统一语义edit事件将添加与关闭两种操作合并为一种签名(paneName, action)。当点击按钮时paneName为undefined、action为add点击某个标签的关闭按钮时paneName为该标签的name、action为remove。使用editable属性时官方推荐统一监听edit分支处理这正是 docs/examples/tabs/dynamic-tabs.vue 的做法。导航条滚动的补充scrollToActiveTab当标签数量超过容器宽度出现横向滚动时可通过 Tabs 暴露的tabNavRef拿到 TabNav 实例并调用其scrollToActiveTab()方法将当前激活标签滚动到可视区域内。该能力对应 Tab-nav Exposes 中的scrollToActiveTab底层配合use-tab-nav-touch.ts支持触摸屏的滑动操作。常见问题可拖拽 / 可排序标签页怎么做官方文档 FAQ 明确说明Tabs 组件本身不内置拖拽排序能力但官方已暴露实现该能力所需的全部必要信息社区通用做法是原生实现监听标签的mousedown/mousemove/mouseup自行计算拖拽偏移并重新排序 pane 数据再通过v-model与受控数据驱动标签顺序。借助成熟拖拽库使用 SortableJS 这类拖拽库将其挂载到标签导航条容器可通过tabNavRef拿到对应 DOM上拖拽结束后依据新顺序重排el-tab-pane的渲染列表。两种思路都建立在标签顺序由业务数据驱动这一受控模式之上——只要你的标签列表是可响应式数组拖拽排序便天然可行。官方文档同时给出了对应的实现 demo 链接可在文档 FAQ 章节 中查看。小结围绕 Element Plus 的 Tabs 组件本文依次覆盖了基础用法与v-model受控切换、card/border-card两种卡片形态、tab-position四种方位布局、#label插槽自定义标签、editable/addable/closable驱动的可增删标签页含edit、tab-remove与自定义添加图标、default-value与before-leave的激活控制、stretch与tabindex等高级属性以及完整的 Tabs / Tab-nav / Tab-bar / Tab-pane API 参考和源码级工作机制。掌握这些内容后从简单的静态标签导航到复杂的管理后台多标签工作台你都可以基于 Element Plus Tabs 快速落地并按需定制。【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考