关于web端的右键功能常用的地方有表格的右键,或者tab标签的右键等,本文记录一下封装一个右键菜单组件的思路步骤代码。
程序员除了会用轮子,还要尝试去贴合自己公司业务场景造轮子。
我们先看一下右键组件的效果图
我们观察这个右键菜单,可以明白右键菜单就是一个ul
标签包裹着很多li
标签的弹出层组件,如下图:
每一行都是一个li,每一行中包含图标
和行按钮
名称文字,于是我们的dom结构
可以这样写:
复制数据
如何考虑菜单组件接收哪些参数呢?
主要是想组件中会使用到哪些变量。如下:
综上所述,我们可以设计右键点击时,要给右键菜单组件传递的参数信息如下:
this.rightclickInfo = {position: {x: event.clientX,y: event.clientY,},menulists: [{fnName: "copy", // 事件名字,组件届时可this.$emit(fnName)抛出事件params: xxx, // 参数,组件届时可this.$emit(fnName,params)抛出事件,并携带参数icoName: "el-icon-document-copy", // 图标名btnName: "复制数据", // 菜单项按钮名// 这三项是发散,可往下看// divided: true, // 是否禁用// disabled: true, // 是否带分隔线// children: [], // 是否有子菜单(递龟)},{fnName: "look",params: { row, column, event },icoName: "el-icon-view",btnName: "查看行数据",},],};
注意,上述参数代码示例中,多了三个参数divided、disabled、children,实际上,参数的设计要结合业务场景,我司的需求没有右键菜单禁用项,也不用有分割线,以及没有右键菜单的子菜单,所以封装组件就暂时没有加上这三个参数。
组件化、模块化的同时,主要高内聚,一个组件满足业务需求,精简为主,不可无节制的死命封装,否则就变成了
诗山代码
了,当然大家也可以仿照真正右键菜单去加功能,比如右键菜单可以绑定快捷键、改成递归形式等更多功能...
所以组件props中接收参数可以写成:
props: {// 接收右键点击的信息rightclickInfo: {type: Object,default: () => {return {position: {// 右键点击的位置x: null,y: null,},menulists: [{fnName: "", // 点击菜单项的事件名params: {}, // 点击的参数icoName: "", // 图标名btnName: "", // 按钮名},],};},},},
不难发现,只要一右键菜单就弹出,点一下菜单消失,这种不停的显示和消失,去不停的v-if
就不合适了,所以这里可以从v-show
的角度出发
display:none
,而后再设置成dispaly:block
position
的x和y
的值就会发生变化watch
监听这个变化,position的x、y
值变了,说明右键点击了通过上述五点,我们即做到了显示隐藏菜单面板了
这一块的思路请看代码中注释即可,如下:
.table-right-menu {dispaly:none; // 初始为隐藏,监听更改显示
}watch: {// 监听右键点击时点击位置的变化,只要变化了,就弹出右键菜单供用户点击操作"rightclickInfo.position"(val) {let x = val.x; // 获取x轴坐标let y = val.y; // 获取y轴坐标let innerWidth = window.innerWidth; // 获取页面可是区域宽度,即页面的宽度let innerHeight = window.innerHeight; // 获取可视区域高度,即页面的高度/*** 注意,这里要使用getElementsByClassName去选中对应dom,因为右键菜单组件可能被多处使用* classIndex标识就是去找到对应的那个右键菜单组件的,需要加的* */ let menu =document.getElementsByClassName("table-right-menu")[this.classIndex]; menu.style.display = "block"; // 由隐藏改为显示let menuHeight = this.rightclickInfo.menulists.length * 30; // 菜单容器高let menuWidth = 180; // 菜单容器宽// 菜单的位置计算(边界留点间隙空间)menu.style.top =(y + menuHeight > innerHeight ? innerHeight - menuHeight : y) + "px";menu.style.left =(x + menuWidth > innerWidth ? innerWidth - menuWidth : x) + "px";// 因为菜单还要关闭,就绑定一个鼠标点击事件,通过e.button判断点击的是否是左键,左键关闭菜单document.addEventListener("mouseup", this.hide, false);},},hide(e) {if (e.button === 0) {// 0是左键、1是滚轮按钮或中间按钮(若有)、2鼠标右键let menu = document.querySelector(".table-right-menu");menu.style.display = "none"; // 菜单关闭document.removeEventListener("mouseup", this.hide); // 及时解绑监听事件}
},
事件绑定后别忘了解绑 document.removeEventListener("mouseup", this.hide);
e.button
e.button
,鼠标事件具体返回数字值,表示鼠标事件发生时按下的鼠标按钮。
可能的值:
0:鼠标左键、 1:滚轮按钮或中间按钮(如果有)、 2:鼠标右键
IE8返回有一些不同:1:鼠标左键、 2:鼠标右键、 4:滚轮按钮或中间按钮(如果有)
注意:左手鼠标,返回值相反
item即为循环的菜单项,包含事件名、参数、图标名、按钮名
fnHandler(item) {this.$emit(item.fnName, item.params);// 事件再传出去,即为:// this.$emit('事件名',事件参数)
},
如下:
el-table中可以使用封装好的事件:@row-contextmenu="xxx"
然后在xxx方法中去传递参数给右键菜单组件即可,如下简化代码:
...
rightclickInfo:{}// 饿了么UI封装好的右键菜单事件,可直接使用,有行数据,列数据,以及事件
rightclick(row, column, event) {this.rightclickInfo = {position: {x: event.clientX,y: event.clientY,},menulists: [{fnName: "copy",params: { row, column, event },icoName: "el-icon-document-copy",btnName: "复制数据",},],};event.preventDefault(); // 阻止默认的鼠标右击事件
},
event.preventDefault()
要加上,阻止默认的右键菜单事件
也同理,传参的时,需要阻止默认时间,如下:
区域内右键onContextmen(){// 定义参数传递给my-right-menu组件
}
复制粘贴即可使用哦
表格内右键
区域内右键
{{ item.btnName }}
上一篇:xxl-job 的 API 接口添加任务的 Java 源代码
下一篇:家用轿车哪款比较好?家用轿车排行榜前十名2022(家用轿车排行榜2021前十名) 长安2022新款家用轿车 2022家用轿车推荐