如何利用Vue3+Element Plus实现动态标签页及右键菜单
1 前言
1.1 目的
Tabs 动态标签页实现右键菜单【关闭当前标签页】、【关闭左侧标签页】、【关闭右侧标签页】、【关闭其他标签页】、【关闭全部标签页】功能
1.2 普通右键菜单
网上使用比较多的是v-contextmenu
插件实现右键菜单,但该插件对于v-for
循环生成的元素失效,插件内部右键菜单显示执行的是emit('show')
未传入当前元素节点(可能后续会修复),且样式需要自行修改
1.3 本文右键菜单方式
本文使用element-plus
自带的el-dropdown
实现右键菜单
2 生成动态标签页
2.1 准备变量容器
<script setup lang="ts"> import { ref } from 'vue' interface TabType { title: string //标签页显示名称 componentName: string //动态组件名 data: any //动态组件传参 } interface TabListType extends TabType { name: string //标签页唯一标识,添加标签页时根据 componentName 自动生成 } const tabList = ref<TabListType[]>([]) //存放标签页数组 const tabValue = ref('home') //存放当前激活标签页,默认激活首页 </script>
2.2 构造标签页
- 可动态添加标签页
- 除【首页】外,可动态移除标签页
<template> <el-tabs v-model="tabValue" type="card" @tab-remove="removeTab"> <el-tab-pane label="首页" name="home"> <Home /> </el-tab-pane> <el-tab-pane v-for="item in tabList" :name="item.name" :key="item.name" closable> <component :is="item.componentName" v-bind="item.data"> </component> </el-tab-pane> </el-tabs> </template>
2.3 动态添加标签页
const addTab = (tab: TabType) => { //保证相同组件路径标签页 name 标识唯一 const name = `${tab.componentName}_${Date.now()}` tabList.value.push({ ...tab, name }) tabValue.value = name } addTab({ title: '标签1', componentName: 'tag1', data: { test: '这是测试数据' } })
2.4 动态移除标签页
const removeTab = (targetName: string) => { const index = tabList.value.findIndex((item) => item.name === targetName) tabList.value.splice(index, 1) //当前激活标签页与触发右键菜单标签页是同一页 if (targetName === tabValue.value) { //当前激活标签页是标签页数组的第一个,则将激活标签页设置为 home //当前激活标签页不是标签页数组的第一个,则将激活标签页设置为当前激活标签页的前一页 tabValue.value = index === 0 ? 'home' : tabList.value[index - 1].name } } removeTab('tag1')
3 生成右键菜单
3.1 扩展标签页
<template> <el-tabs v-model="tabValue" type="card" @tab-remove="removeTab"> <el-tab-pane label="首页" name="home"> <Home /> </el-tab-pane> <el-tab-pane v-for="item in tabList" :name="item.name" :key="item.name" closable> <!-- 右键菜单开始:自定义标签页显示名称,保证每个标签页都能实现右键菜单 --> <template #label> <el-dropdown trigger="contextmenu" :id="item.name" @visible-change="handleChange($event, item.name)" ref="dropdownRef" > <span :class="tabValue === item.name ? 'label' : ''">{{ item.title }}</span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item @click="removeTab(item.name)"> <el-icon><Close /></el-icon>关闭当前标签页 </el-dropdown-item> <el-dropdown-item @click="removeTab(item.name, 'left')" v-if="show(item.name, 'left')" > <el-icon><DArrowLeft /></el-icon>关闭左侧标签页 </el-dropdown-item> <el-dropdown-item @click="removeTab(item.name, 'right')" v-if="show(item.name, 'right')" > <el-icon><DArrowRight /></el-icon>关闭右侧标签页 </el-dropdown-item> <el-dropdown-item @click="removeTab(item.name, 'other')" v-if="tabList.length > 1" > <el-icon><Operation /></el-icon>关闭其他标签页 </el-dropdown-item> <el-dropdown-item @click="removeTab(item.name, 'all')"> <el-icon><Minus /></el-icon>关闭全部标签页 </el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </template> <!-- 右键菜单结束 --> <component :is="item.componentName" v-bind="item.data"> </component> </el-tab-pane> </el-tabs> </template>
3.2 增加 show 方法
- 触发右键菜单标签页为第一个时,不展示【关闭左侧标签页】
- 触发右键菜单标签页为最后一个时,不展示【关闭右侧标签页】
const show = (name: string, type: string) => { const index = tabList.value.findIndex((item) => name === item.name) return type === 'left' ? index !== 0 : index !== tabList.value.length - 1 }
3.3 扩展 removeTab 方法
const removeTab = (targetName: string, type?: string) => { const index = tabList.value.findIndex((item) => item.name === targetName) //查找触发右键菜单所在标签页index const currentIndex = tabList.value.findIndex((item) => item.name === tabValue.value) //查找当前激活标签页index,存在当前激活标签页与触发右键菜单标签页不是同一个的情况 switch (type) { case 'all': //关闭全部标签页 tabList.value = [] //清空除【首页】外所有标签页 tabValue.value = 'home' //修改标签激活页 break case 'other': //关闭其他标签页 tabList.value = [tabList.value[index]] if (targetName !== tabValue.value) { tabValue.value = targetName } break case 'left': //关闭左侧标签页 tabList.value.splice(0, index) if (currentIndex < index) { tabValue.value = targetName } break case 'right': //关闭右侧标签页 tabList.value.splice(index + 1) if (currentIndex > index) { tabValue.value = targetName } break default: //默认关闭当前标签页 tabList.value.splice(index, 1) //当前激活标签页与触发右键菜单标签页是同一页 if (targetName === tabValue.value) { //当前激活标签页是标签页数组的第一个,则将激活标签页设置为 home //当前激活标签页不是标签页数组的第一个,则将激活标签页设置为当前激活标签页的前一页 tabValue.value = index === 0 ? 'home' : tabList.value[index - 1].name } break } }
3.4 解决重复出现菜单问题
当连续在多个标签页触发右键时,会出现多个菜单,解决方案为:在触发右键菜单后,关闭其他右键菜单
const dropdownRef = ref() const handleChange = (visible: boolean, name: string) => { if (!visible) return dropdownRef.value.forEach((item: { id: string; handleClose: () => void }) => { if (item.id === name) return item.handleClose() }) }
3.5 解决自定义标签样式问题
<style lang="scss" scoped> .label { color: var(--el-color-primary); //激活标签页高亮 } :deep(.el-tabs__item) { &:hover { span { color: var(--el-color-primary); //鼠标移到标签页高亮 } } .el-dropdown { line-height: inherit; // 统一标签页显示名称行高 } } </style>
总结
到此这篇关于如何利用Vue3+Element Plus实现动态标签页及右键菜单的文章就介绍到这了,更多相关Vue3 Element Plus动态标签页及右键菜单内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
vue中使用Cesium加载shp文件、wms服务、WMTS服务问题
这篇文章主要介绍了vue中使用Cesium加载shp文件、wms服务、WMTS服务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-05-05基于vue2框架的机器人自动回复mini-project实例代码
本篇文章主要介绍了基于vue2框架的机器人自动回复mini-project实例代码,具有一定的参考价值,有兴趣的可以了解一下2017-06-06
最新评论