Electron for OpenHarmony 实战:Tabs 标签页组件实现 PC适配

页面内容太多时,把所有东西堆在一起会让用户眼花缭乱。Tabs 标签页可以把内容分成几个类别,用户点击不同的标签查看不同的内容,页面结构清晰很多。这篇文章来聊聊在 Electron for OpenHarmony 项目中如何使用 Tabs 标签页组件。
Tabs 的使用场景
标签页在很多地方都能用到:后台管理系统的功能模块切换、用户中心的个人信息和设置分开展示、商品详情页的描述和评价分开、编辑器的多文件切换等等。
相比用多个页面来展示这些内容,标签页的优势是切换快、不需要页面跳转、能保持上下文状态。用户在不同标签之间切换时,之前填写的表单数据不会丢失。
控制当前激活的标签
标签页通过 v-model 绑定当前激活的标签:
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const activeName = ref('first')
</script>
activeName 存储当前激活标签的 name 值,初始值 'first' 表示默认显示第一个标签的内容。切换标签时这个值会自动更新,也可以在代码中修改它来切换标签。
基础标签页
最简单的标签页由 el-tabs 和 el-tab-pane 组成:
<el-card class="demo-card">
<template #header>基础用法</template>
<el-tabs v-model="activeName">
<el-tab-pane label="用户管理" name="first">用户管理内容</el-tab-pane>
<el-tab-pane label="配置管理" name="second">配置管理内容</el-tab-pane>
<el-tab-pane label="角色管理" name="third">角色管理内容</el-tab-pane>
</el-tabs>
</el-card>
el-tabs 是标签页容器,el-tab-pane 是每个标签面板。label 是标签上显示的文字,name 是标签的唯一标识,用来和 v-model 绑定的值对应。
点击不同的标签,下方会显示对应的内容。当前激活的标签会有高亮样式和下划线指示器。
卡片风格
默认的标签页是线条风格,还可以用卡片风格:
<el-card class="demo-card">
<template #header>卡片风格</template>
<el-tabs type="card">
<el-tab-pane label="标签一">标签一内容</el-tab-pane>
<el-tab-pane label="标签二">标签二内容</el-tab-pane>
<el-tab-pane label="标签三">标签三内容</el-tab-pane>
</el-tabs>
</el-card>
type="card" 让标签变成卡片样式,每个标签像一个独立的卡片,激活的标签和内容区域连成一体。这种风格在视觉上更有层次感。
边框卡片风格
还有一种带边框的卡片风格:
<el-card class="demo-card">
<template #header>边框卡片</template>
<el-tabs type="border-card">
<el-tab-pane label="标签一">标签一内容</el-tab-pane>
<el-tab-pane label="标签二">标签二内容</el-tab-pane>
<el-tab-pane label="标签三">标签三内容</el-tab-pane>
</el-tabs>
</el-card>
type="border-card" 给整个标签页加上边框,内容区域有背景色,看起来像一个完整的容器。这种风格适合需要和页面其他内容明显区分的场景。
标签位置
标签默认在顶部,也可以放在其他位置:
<script setup lang="ts">
import { ref } from 'vue'
const tabPosition = ref('top')
</script>
<template>
<el-space style="margin-bottom: 16px;">
<el-radio-group v-model="tabPosition">
<el-radio-button value="top">顶部</el-radio-button>
<el-radio-button value="right">右侧</el-radio-button>
<el-radio-button value="bottom">底部</el-radio-button>
<el-radio-button value="left">左侧</el-radio-button>
</el-radio-group>
</el-space>
<el-tabs :tab-position="tabPosition" style="height: 200px;">
<el-tab-pane label="用户">用户内容</el-tab-pane>
<el-tab-pane label="配置">配置内容</el-tab-pane>
<el-tab-pane label="角色">角色内容</el-tab-pane>
<el-tab-pane label="任务">任务内容</el-tab-pane>
</el-tabs>
</template>
tab-position 属性控制标签位置,可选值是 top、right、bottom、left。左右位置的标签页需要设置高度,不然内容区域会塌陷。
左侧标签页在后台管理系统中很常见,可以做成侧边导航的效果。
带图标的标签
标签上可以加图标让含义更直观:
<el-tabs v-model="activeName">
<el-tab-pane name="user">
<template #label>
<span><el-icon><User /></el-icon> 用户</span>
</template>
用户管理内容
</el-tab-pane>
<el-tab-pane name="setting">
<template #label>
<span><el-icon><Setting /></el-icon> 设置</span>
</template>
设置内容
</el-tab-pane>
<el-tab-pane name="message">
<template #label>
<span><el-icon><Message /></el-icon> 消息</span>
</template>
消息内容
</el-tab-pane>
</el-tabs>
通过 #label 插槽自定义标签内容,可以放图标、徽标或者任何自定义元素。
可关闭的标签
编辑器场景需要能关闭标签:
<script setup lang="ts">
import { ref } from 'vue'
const editableTabsValue = ref('1')
const editableTabs = ref([
{ title: '文档1', name: '1', content: '文档1的内容' },
{ title: '文档2', name: '2', content: '文档2的内容' },
{ title: '文档3', name: '3', content: '文档3的内容' },
])
let tabIndex = 3
const handleTabsEdit = (targetName: string | undefined, action: 'remove' | 'add') => {
if (action === 'add') {
const newTabName = `${++tabIndex}`
editableTabs.value.push({
title: `新文档${tabIndex}`,
name: newTabName,
content: `新文档${tabIndex}的内容`
})
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>
<template>
<el-tabs v-model="editableTabsValue" type="card" editable @edit="handleTabsEdit">
<el-tab-pane
v-for="item in editableTabs"
:key="item.name"
:label="item.title"
:name="item.name"
>
{{ item.content }}
</el-tab-pane>
</el-tabs>
</template>
editable 属性开启可编辑模式,标签上会显示关闭按钮,右侧会显示添加按钮。@edit 事件在添加或删除标签时触发,参数是目标标签的 name 和操作类型。
关闭标签时要处理一个细节:如果关闭的是当前激活的标签,需要自动切换到相邻的标签。上面的代码在删除时会检查这个情况并处理。
动态标签页
标签页的内容可以动态生成:
<script setup lang="ts">
import { ref, computed } from 'vue'
const tabs = ref([
{ name: 'home', label: '首页', content: '首页内容' },
{ name: 'news', label: '新闻', content: '新闻列表' },
{ name: 'about', label: '关于', content: '关于我们' },
])
const activeName = ref('home')
const addTab = () => {
const name = `tab-${Date.now()}`
tabs.value.push({
name,
label: `新标签 ${tabs.value.length + 1}`,
content: `新标签内容 ${tabs.value.length + 1}`
})
activeName.value = name
}
</script>
<template>
<el-button @click="addTab" style="margin-bottom: 16px;">添加标签</el-button>
<el-tabs v-model="activeName">
<el-tab-pane
v-for="tab in tabs"
:key="tab.name"
:label="tab.label"
:name="tab.name"
>
{{ tab.content }}
</el-tab-pane>
</el-tabs>
</template>
用 v-for 遍历数据数组生成标签页,添加新数据就会自动出现新标签。这种方式适合标签数量不固定的场景。
懒加载标签内容
默认情况下所有标签的内容都会渲染,只是不显示。如果内容很重,可以开启懒加载:
<el-tabs v-model="activeName">
<el-tab-pane label="用户" name="user" lazy>
<!-- 这个内容只有在标签被激活时才会渲染 -->
<heavy-component />
</el-tab-pane>
<el-tab-pane label="订单" name="order" lazy>
<another-heavy-component />
</el-tab-pane>
</el-tabs>
lazy 属性让标签内容延迟渲染,只有当标签被激活时才会渲染内容。这可以提升初始加载性能,特别是当标签内容包含复杂组件或需要请求数据时。
标签切换事件
监听标签切换可以做一些额外的操作:
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const activeName = ref('first')
const handleTabClick = (tab: any) => {
ElMessage.info(`切换到: ${tab.props.label}`)
}
const handleBeforeLeave = (activeName: string, oldActiveName: string) => {
// 返回 false 可以阻止切换
if (oldActiveName === 'edit' && hasUnsavedChanges()) {
return confirm('有未保存的更改,确定要离开吗?')
}
return true
}
const hasUnsavedChanges = () => {
// 检查是否有未保存的更改
return true
}
</script>
<template>
<el-tabs v-model="activeName" @tab-click="handleTabClick" :before-leave="handleBeforeLeave">
<el-tab-pane label="查看" name="view">查看内容</el-tab-pane>
<el-tab-pane label="编辑" name="edit">编辑内容</el-tab-pane>
<el-tab-pane label="设置" name="setting">设置内容</el-tab-pane>
</el-tabs>
</template>
@tab-click 在点击标签时触发,before-leave 在切换前调用,返回 false 可以阻止切换。这在编辑场景下很有用,可以提醒用户保存未保存的更改。
与鸿蒙原生能力结合
在 Electron for OpenHarmony 项目中,标签页可以和原生能力配合使用:
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useOhos } from '@/composables/useOhos'
import { ElMessage } from 'element-plus'
const { setWindowTitle, showNotification } = useOhos()
const activeName = ref('files')
const tabs = [
{ name: 'files', label: '文件管理', title: '文件管理器' },
{ name: 'settings', label: '系统设置', title: '系统设置' },
{ name: 'about', label: '关于', title: '关于本应用' },
]
watch(activeName, (newName) => {
const tab = tabs.find(t => t.name === newName)
if (tab) {
setWindowTitle(tab.title)
}
})
const handleTabChange = async (tab: any) => {
if (tab.props.name === 'settings') {
await showNotification('提示', '您正在进入系统设置')
}
}
</script>
<template>
<el-tabs v-model="activeName" @tab-click="handleTabChange">
<el-tab-pane
v-for="tab in tabs"
:key="tab.name"
:label="tab.label"
:name="tab.name"
>
<div style="padding: 20px;">
{{ tab.label }} 的内容区域
</div>
</el-tab-pane>
</el-tabs>
</template>
这个例子展示了两个原生能力的使用:切换标签时通过 setWindowTitle 更新窗口标题,让标题和当前内容对应;进入特定标签时通过 showNotification 发送系统通知提醒用户。
禁用某个标签
某些标签可能暂时不可用:
<el-tabs v-model="activeName">
<el-tab-pane label="可用" name="enabled">可用内容</el-tab-pane>
<el-tab-pane label="禁用" name="disabled" disabled>禁用内容</el-tab-pane>
<el-tab-pane label="也可用" name="also-enabled">也可用内容</el-tab-pane>
</el-tabs>
disabled 属性禁用标签,禁用的标签会变灰且不可点击。可以根据权限或状态动态设置这个属性。
样式定制
Tabs 的样式可以通过 CSS 变量调整:
.el-tabs {
--el-tabs-header-height: 40px;
}
.el-tabs__item {
padding: 0 20px;
font-size: 14px;
}
.el-tabs__item.is-active {
color: #409eff;
font-weight: bold;
}
.el-tabs__active-bar {
background-color: #409eff;
height: 3px;
}
可以调整标签的高度、内边距、字体大小、激活状态的颜色和下划线样式,让标签页和你的设计风格保持一致。
小结
Tabs 标签页是内容组织的重要组件,这篇文章介绍了它的各种用法:三种风格样式、四个标签位置、带图标的标签、可关闭的标签、动态标签页、懒加载、切换事件,以及与鸿蒙原生能力的结合。标签页的核心是通过 v-model 控制当前激活的标签,通过 el-tab-pane 定义每个标签的内容。合理使用标签页可以让复杂的页面结构变得清晰有序。
欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)