Fork me on GitHub

右键自定义菜单

自定义菜单

最近的后台管理项目中使用到了右侧标签栏方便用户切换不同模块。但当标签栏过多时一个个关闭明显示是反人类的,所以参考了element admin后写了一个自定义指令来实现点击鼠标右键实现自定义菜单。

最终效果图:


结构代码

ui部分

html代码:

1
2
3
4
5
6
7
8
9
<div class="tags_div" v-menus>
<el-tag>右键点击</el-tag>
<ul class="contextmenu" :style="{'left': menuLeft, 'top': menuTop}" v-show="menuShow">
<li>刷新</li>
<li>关闭</li>
<li>关闭其它</li>
<li>关闭所有</li>
</ul>
</div>

css代码:

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
.tags_div {
margin-top: 30px;
position: relative;
display: inline-block;
cursor: pointer;
}

.contextmenu {
margin: 0;
background: #fff;
width: 100px;
z-index: 100;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, .3)
}

.contextmenu li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
}

.contextmenu li:hover {
background: #eee;
}

这块没什么好说的,主要是设置子相父绝定位,鼠标点击的时候好去设置菜单栏的位置。

自定义指令实现右键菜单栏

自定义指令我在上篇已经介绍过了,这里主要说一下设计到的相关事件和属性(上篇自定义拖拽弹窗介绍过的这里不再列出)。

相关属性(事件对象event,dom元素)

  1. event.pageX:pageX事件属性返回当事件被触发时鼠标指针向对于htmlbody的水平坐标。
  2. event.pageY:pageY事件属性返回当事件被触发时鼠标指针向对于htmlbody垂直坐标。
  3. offsetParent属性:可以返回当前元素上个定位父级元素。

相关事件

  1. oncontextmenu:事件在元素中用户点击鼠标右键时触发。
  2. onmouseup:在用户松开鼠标按键时触发。

实现代码

vue代码:

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
52
53
54
55
56
directives: {
menus: {
inserted: function (el, binding, vnode) {
//获取vue实例对象
let vm = vnode.context;
let showFlag = true;
vnode = vnode.elm;
//阻止默认浏览器的右键菜单
el.oncontextmenu = ((event) => {
event.preventDefault();
});
el.onmouseup = ((event) => {
if (event.button === 2) {
vm.menuShow = true;
showFlag = false;
let realTop = vm.getElementToPageTop(vnode);
let realLeft = vm.getElementToPageLeft(vnode);
let top = event.pageY - realTop + 5 + 'px';
let left = event.pageX - realLeft + 5 + 'px';
vm.menuLeft = left;
vm.menuTop = top;
}
});
document.onmouseup = (() => {
if (showFlag) {
vm.menuShow = false;
}
showFlag = true;
});
}
}
}

//vue实例数据
data() {
return {
menuShow: false,
menuLeft: 0,
menuTop: 0,
}
},
//获取当前元素距离body原点的距离
methods: {
getElementToPageTop: function (el) {
if (el.offsetParent) {
return this.getElementToPageTop(el.offsetParent) + el.offsetTop;
}
return el.offsetTop;
},
getElementToPageLeft: function (el) {
if (el.offsetParent) {
return this.getElementToPageLeft(el.offsetParent) + el.offsetLeft;
}
return el.offsetLeft;
}
}

分析

  1. 首先是通过oncontextmenu阻止浏览器的上下文菜单,在绑定onmouseup事件判断鼠标右键点击。
  2. 获取当前元素距离body顶端的距离,在与鼠标在页面中的实际距离想减获取鼠标在div中的位置,进而设置菜单栏出现的位置。
  3. document绑定onmouseup事件,点击页面其他地方关闭菜单栏。

注意点

  1. 获取当前元素距离body顶端的距离要判断当前元素有没有上级定位元素,如果有当前元素距离body顶端的距离是它的距离body顶端的距离与定位父级距离body顶端的距离之和。这里我写了两个递归来实现距离的计算getElementToPageTopgetElementToPageLeft
  2. 点击其它的地方关闭菜单栏,这里在自定义指定的元素上点击右键时设置了一个标识,只有当这个标识为false的时候才不会关闭菜单栏。

结语

这个方法可以用来实现禁止剪切和复制网页内容…

----------本文结束感谢您的阅读-----------
谢谢打赏,好人一生平安