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

目录
  • 1 前言
    • 1.1 目的
    • 1.2 普通右键菜单
    • 1.3 本文右键菜单方式
  • 2 生成动态标签页
    • 2.1 准备变量容器
    • 2.2 构造标签页
    • 2.3 动态添加标签页
    • 2.4 动态移除标签页
  • 3 生成右键菜单
    • 3.1 扩展标签页
    • 3.2 增加 show 方法
    • 3.3 扩展 removeTab 方法
    • 3.4 解决重复出现菜单问题
    • 3.5 解决自定义标签样式问题
  • 总结

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动态标签页及右键菜单内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用ElementUI修改el-tabs标签页组件样式

    目录 ElementUI修改el-tabs标签页组件样式 效果图 ElementUI的el-tabs标签页样式冲突问题 修改样式即可 ElementUI修改el-tabs标签页组件样式 官方示例:https://element.eleme.cn/#/zh-CN/component/tabs 效果图 <el-tabs v-model="activeName" @tab-click="handleClick" :stretch="false"

  • Vue + Elementui实现多标签页共存的方法

    这个主题,早在一年前就已经创建,也写了一些内容,碍于在应用上体验始终不够完美,一直只存着草稿. 经过多个平台实践,多次迭代,一些功能加了又减了,最后还是回归了最精简的版本,已适用于大部分的场景,若有需要,可自行扩展. 关键逻辑 使用 keep-alive 来缓存各标签页 通过 vue-router 的 beforeEach 方法来更新标签信息 通过 vuex 来保存标签信息 通过 vuex 来使关闭页不被缓存 核心代码 定义 vuex 的跨页变量(store/index.js) import V

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

    目录 1 前言 1.1 目的 1.2 普通右键菜单 1.3 本文右键菜单方式 2 生成动态标签页 2.1 准备变量容器 2.2 构造标签页 2.3 动态添加标签页 2.4 动态移除标签页 3 生成右键菜单 3.1 扩展标签页 3.2 增加 show 方法 3.3 扩展 removeTab 方法 3.4 解决重复出现菜单问题 3.5 解决自定义标签样式问题 总结 1 前言 1.1 目的 Tabs 动态标签页实现右键菜单[关闭当前标签页].[关闭左侧标签页].[关闭右侧标签页].[关闭其他标签页].

  • 如何利用Vue3管理系统实现动态路由和动态侧边菜单栏

    目录 前言 动态路由 动态侧边菜单栏 总结 前言 在做Vue管理系统的时候,都会遇到的一个需求:每个用户的权限是不一样的,那么他可以访问的页面(路由),可以操作的菜单选项是不一样的,如果由后端控制,我们前端需要去实现动态路由,动态渲染侧边菜单栏. 动态路由 在本示例管理系统中,由于每个用户的权限不一样,拥有的可以访问的路由页面也不一样,用户能访问的路由页面都是后端根据权限动态配置的 我们前端需要根据后端接口返回的路由表去动态增删路由,从而生成这个用户所拥有的路由. 重点:实现动态路由api ro

  • Vue.js如何利用v-for循环生成动态标签

    目录 前言 一.当写入数据为数组时 二.当写入数据为对象时 三.作用于标签属性和事件 总结 前言 使用v-for可以用于动态生成html标签.其实就是对于vue中属性是对象或者数组进行遍历生成新的标签. v-for就像java中的for循环一样,迭代需要的所有元素. 大多数情况是以一个数组嵌套多个对象的数据进行v-for循环 一.当写入数据为数组时 如果循环遍历得到的value值是一个对象,需要使用里面的值可以用 对象名.key 来调用key对应的value值 v-for写入数组的格式: arr

  • 利用Vue3实现拖拽定制化首页功能

    目录 前期准备 开始 方法一 方法二 方案三 最终实现结果 总结 前期准备 Vue3 Ts VueDragable (4版本以上) 期望 拖拽组件 组件可以按需加载导入 开始 首先呢,我们先看下VueDragable的文档效果 文档的效果是这种基于列表的一个拖拽排序,那么回归到我们期望我们是想通过动态引入组件来进行拖拽排序,那么在完成拖拽定制化之前,首先要讲的是动态组件,在使用Vue2时候相信我们不陌生我们可以通过Component is来动态引入,如: <template> <div

  • vue3 element的Form表单用法实例

    目录 引言 设计目标 配置化 参数简单 自由度 实现过程 表单项的格式设计 v-bind的妙用 computed的妙用:实现v-model useAttrs的妙用 表单验证 上传文件 代码总结 到底应不应该使用json 需不需要v-model 性能问题 引言 最近在做一系列后台管理系统,其中用的最多的就是表单和表格了.这里讲一下我最近对表单封装的思考. 以下是我的设计思路以及具体实现,我使用的是vue3+element-plus,因此这个组件也是以这两个库为基础. 已上传npm www.npmj

  • 详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)

    在 vue 中,实现 Tab 切换主要有三种方式:使用动态组件,使用 vue-router 路由,使用第三方插件. 因为这次完成的功能只是简单切换组件,再则觉得使用路由切换需要改变地址略微麻烦,所以使用的是动态组件实现,如果是在大型应用上,可能使用 vue-router 会方便一些. 先看下最终实现的效果,结构比较简单,顶部的三个 Tab 标签用于切换,内容区域分别为三个子组件. 效果预览 关键代码及分析如下: <template> // 每一个 tab 绑定了一个点击事件,传入的参数对应着

  • vue2.* element tabs tab-pane 动态加载组件操作

    一.重要部分 1. 注意 <component :is=item.content></component> :表明模板 <el-tab-pane v-for="(item) in editableTabs" :key="item.name" :label="item.title" :name="item.name" > <component :is=item.content>&l

  • 利用Vue3实现一个可以用js调用的组件

    目录 前言 一.常规Vue组件 1. 组件主要代码: 2. 使用方式 3. 实现效果 二.改为js调用组件 1. 实现步骤: 2. 具体实现代码: 3. 实现效果展示 总结 前言 项目开发中基本都会用到组件库,但是设计稿样式和功能不一定和组件库相同,尤其像是消息提示弹窗.确认弹窗,各个项目各个设计师都有自己的一套风格.虽然我们可以使用组件库中的组件对其进行样式覆盖来使用.但是一些定制功能还是不容易修改,这种情况我们就会选择自定义组件,然后通过 components 属性引入页面,显式写入标签调用

  • 利用vue3自己实现计数功能组件封装实例

    目录 前言 一.封装的意义 二.如何封装? 1. 思路 2. 准备 2. 使用 三. 效果演示 总结 前言 本文将带你用vue3自己封装一个实现计数功能的全局组件,其应用场景相信各位一看便知,那就是购物网站中常见的数量选择模块,一起来看看如何实现哇 一.封装的意义 项目中需要用到的地方较多 模块化开发,降低了代码冗余,是开发更加高效 一次封装,到处使用 二.如何封装? 1. 思路 使用vue3中v-model来完成父子组件之间的相互传值,本文章使用vueuse/core中封装好的useVMode

  • 如何利用Vue3+Vite批量导入模块/资源

    目录 前言 1,前置基础知识-JavaScript模块化编程 (1)export语句-暴露函数和变量使外部调用 (2)import语句-导入变量/函数并使用 (3)import*asxxx语句-全部导入 (4)exportdefault-默认导出 2,在Vite工程中批量导入js模块 3,在Vite工程中批量导入图片/音频等静态资源 总结 前言 在Vue项目开发中,我们常常会导入一些外部的模块,或者是自己写模块导入. 但是模块多了,一个个地导入很显然不是一个好办法,因此我们可以批量导入. 1,前

随机推荐