电商商城定制开发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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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: '这是测试数据'  }})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

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}
  • 1
  • 2
  • 3
  • 4

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  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

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()  })}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发