转载请注明原文地址
大体思路类似,具体实现在于控件是否提供了右键菜单的回调方法. 右键菜单的样式也可以根据自己需求进行变更.
新版本
- 基于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>
爱你三千遍❤