如何利用Vue3+Element Plus实现动态标签页及右键菜单

 更新时间:2022年11月15日 08:51:26   作者:YanaDH  
标签页一般配合菜单实现,当你点击一级菜单或者二级菜单时,可以增加对应的标签页,当你点击对应的标签页,可以触发对应的一级菜单或者二级菜单,下面这篇文章主要给大家介绍了关于如何利用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服务问题

    这篇文章主要介绍了vue中使用Cesium加载shp文件、wms服务、WMTS服务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • ElementUI之Message功能拓展详解

    ElementUI之Message功能拓展详解

    这篇文章主要介绍了ElementUI之Message功能拓展详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 基于vue2框架的机器人自动回复mini-project实例代码

    基于vue2框架的机器人自动回复mini-project实例代码

    本篇文章主要介绍了基于vue2框架的机器人自动回复mini-project实例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-06-06
  • 详解vue-cli项目在IE浏览器打开报错解决方法

    详解vue-cli项目在IE浏览器打开报错解决方法

    这篇文章主要介绍了详解vue-cli项目在IE浏览器打开报错解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • vue项目的创建的步骤(图文教程)

    vue项目的创建的步骤(图文教程)

    本文主要介绍了vue项目的创建的步骤(图文教程),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Vue+UpLoad实现上传预览和删除图片的实践

    Vue+UpLoad实现上传预览和删除图片的实践

    本文主要介绍了Vue+UpLoad实现上传预览和删除图片的实践,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 微信小程序实战基于vue2实现瀑布流的代码实例

    微信小程序实战基于vue2实现瀑布流的代码实例

    瀑布流,又称瀑布流式布局,是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部,这篇文章主要介绍了微信小程序实战,基于vue2实现瀑布流,需要的朋友可以参考下
    2022-12-12
  • Vue函数式组件专篇深入分析

    Vue函数式组件专篇深入分析

    Vue提供了一种称为函数式组件的组件类型,用来定义那些没有响应数据,也不需要有任何生命周期的场景,它只接受一些props来显示组件,下面这篇文章主要给大家介绍了关于Vue高级组件之函数式组件的使用场景与源码分析的相关资料,需要的朋友可以参考下
    2023-01-01
  • vue.js使用3DES加密的方法示例

    vue.js使用3DES加密的方法示例

    这篇文章主要介绍了vue.js使用3DES加密的方法,结合实例形式分析了vue.js使用3DES加密的具体操作步骤与使用技巧,并提供了CryptoJS-v3.1.2的本地下载,需要的朋友可以参考下
    2018-05-05
  • Vue自定义表单内容检查rules实例

    Vue自定义表单内容检查rules实例

    这篇文章主要介绍了Vue自定义表单内容检查rules实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10

最新评论