vue+element-UI实现右键菜单

转载请注明原文地址
大体思路类似,具体实现在于控件是否提供了右键菜单的回调方法. 右键菜单的样式也可以根据自己需求进行变更.

新版本

  • 基于vue3
  • 支持自动调整偏移量,防止菜单超出屏幕

封装rightMenu组件

<!--
 * @Description: 右键菜单
 * @Author: r_yuesheng
 * @Date: 2021-08-09 16:13:32
 * @LastEditTime: 2021-011-09 17:33:07
 * @LastEditors: r_yuesheng
-->
<template>
  <div>
    <ul :id="rightType" class="rightmenu" v-show="menuVisible">
      <li
        class="menu_item"
        :style="menu.customStyle"
        v-for="(menu, menuIndex) in menuOptions"
        :key="menuIndex"
        @click="menuClick(menu)"
      >
        <i :class="menu.icon"></i>
        <span>{
    
    {
    
     menu.label }}</span>
      </li>
    </ul>
  </div>
</template>

<script>
import {
    
     reactive, toRefs, watch } from "vue";
export default {
    
    
  emits: ["backEvent"],
  name: "rightMenu",
  props: {
    
    
    //右键类型,目前只有两种 table和tree
    rightType: String,
    //禁用按钮
    menuDisabled: {
    
    
      type: Array,
      default: () => {
    
    },
    },
    //是否显示
    menuVisible: Boolean,
    //鼠标事件
    menuEvent: Object,
    //自定义右键菜单内容
    menuOptions: {
    
    
      type: Array,
      default: () => {
    
    
        return [
          {
    
    
            label: "新建",
            icon: "el-icon-folder-add r_menu_icon",
            event: "create",
          },
        ];
      },
    },
  },
  setup(props, {
     
      emit }) {
    
    
    const state = reactive({
    
    
      listType: ["table", "tree"],
      currViewPortHeight: document.body.clientHeight,
      menuLenth: 100,
    });
    watch(
      () => props.menuEvent,
      (value) => {
    
    
        state.listType.forEach((item) => {
    
    
          const menu = document.querySelector(`#${
      
      item}`);
          if (menu) {
    
    
            menu.style.display = "none";
          }
        });
        initMenuDisable();
        state.currViewPortHeight = document.body.clientHeight;
        state.menuLenth = props.menuOptions.length * 38;
        // const tempMouseEvent = value.MouseEvent;
        treeRightClick();
      }
    );
    watch(
      () => props.menuVisible,
      (value) => {
    
    
        if (!value) {
    
    
          foo();
        }
      }
    );
    function menuClick(type) {
    
    
      emit("backEvent", type.event);
      foo();
    }
    function treeRightClick() {
    
    
      const {
    
     MouseEvent } = props.menuEvent;
      const menu = document.querySelector(`#${
      
      props.rightType}`);
      menu.style.display = "";
      window.event.returnValue = false;
      const tempCurrMenuHeight = MouseEvent.clientY + state.menuLenth;
      menu.style.left = `${
      
      MouseEvent.clientX + 10}px`;
      if (tempCurrMenuHeight > state.currViewPortHeight) {
    
    
        menu.style.top = `${
      
      state.currViewPortHeight - state.menuLenth - 50}px`;
      } else {
    
    
        menu.style.top = `${
      
      MouseEvent.clientY - 40}px`;
      }
      document.addEventListener("click", foo);
    }
    function foo() {
    
    
      emit("backEvent", null);
      document.removeEventListener("click", foo);
    }
    function initMenuDisable() {
    
    
      props.menuOptions.forEach((item) => {
    
    
        if (props.menuDisabled.includes(item.event)) {
    
    
          item.customStyle = "pointer-events:none;color:#c5cbd8;";
        } else {
    
    
          item.customStyle = "";
        }
      });
    }
    return {
    
    
      ...toRefs(state),
      menuClick,
      foo,
      treeRightClick,
    };
  },
};
</script>

<style scoped>
.rightmenu {
    
    
  padding: 0 15px;
  position: absolute;
  border-radius: 4px;
  background-color: #fff;
  padding: 5px 0;
  text-align: left;
  box-shadow: 0 3px 6px 3px #dbdde5;
  z-index: 2;
  color: #4d556f;
}
.rightmenu .menu_item {
    
    
  display: block;
  line-height: 28px;
  text-align: left;
  padding: 4px 12px;
  font-size: 14px;
}
.rightmenu li:hover {
    
    
  background-color: #4671ff;
  color: #fff;
  cursor: pointer;
  transition: ease all 0.2s;
}
</style>

页面使用

基于el-tree使用

<template>
  <RightMenu
    rightType="tree" 
    :menuVisible="showTreeMenu"
    :menuEvent="objectTreeMenuEvent"
    :menuOptions="objMenuOptions"
    @backEvent="backEvent"
  ></RightMenu>
</template>
<script>
import RightMenu from './rightMenu.vue';//引入右键菜单组件
</script> 

基于el-table使用

  <TableRightMenu
    :menuVisible="tableRightMenu"
    :menuDisabled="listMenuDisabled"
    rightType="table"
    :menuEvent="objectTableMenuEvent"
    :menuOptions="objMenuOptions"
    @backEvent="backEvent"
  ></TableRightMenu>

旧版本

1.右键菜单的样式

    <div v-show="menuVisible">
    		<ul id="menu" class="menu">
    				<li class="menu__item">新增</li>
    				<li class="menu__item">重命名</li>
    				<li class="menu__item">删除</li>
    		</ul>
    </div>
    
.menu__item {
    
    
	display: block;
	line-height: 20px;
	text-align: center;
	margin:10px;
	cursor: default;
}
.menu__item:hover{
    
    
	color: #FF0000;
}

.menu {
    
    
 	height: auto;
 	width: auto;
 	position: absolute;
 	font-size: 14px;
 	text-align: left;
 	border-radius: 10px;
 	border: 1px solid #c1c1c1;
 	background-color: #ffffff;
}

li:hover {
    
    
  background-color: #E0E0E2;
  color: white;
}

2.公用方法

method:{
    
    
    rightClick(row, event) {
    
    
      this.menuVisible = false; // 先把模态框关死,目的是 第二次或者第n次右键鼠标的时候 它默认的是true
      this.menuVisible = true; // 显示模态窗口,跳出自定义菜单栏
      var menu = document.querySelector('#menu');
      this.styleMenu(menu);
    },
    foo() {
    
    
      // 取消鼠标监听事件 菜单栏
      this.menuVisible = false;
      document.removeEventListener('click', this.foo); // 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
    },
    styleMenu(menu) {
    
    
      if (event.clientX > 1800) {
    
    
        menu.style.left = event.clientX - 100 + 'px';
      } else {
    
    
        menu.style.left = event.clientX + 1 + 'px';
      }
      document.addEventListener('click', this.foo); // 给整个document新增监听鼠标事件,点击任何位置执行foo方法
      if (event.clientY > 700) {
    
    
        menu.style.top = event.clientY - 30 + 'px';
      } else {
    
    
        menu.style.top = event.clientY - 10 + 'px';
      }
    }
}

3.选择一种方式,自行绑定数据

第一种: el-tree 树形式
在这里插入图片描述

 <el-tree :data="templateData" :prop="templateData.tempName"  @node-contextmenu="rightClick"></el-tree>

第二种 el-table 表格形式
在这里插入图片描述

<el-table :data="Data"   @row-contextmenu="rightClick"></el-table>

爱你三千遍❤

猜你喜欢

转载自blog.csdn.net/r657225738/article/details/90479983