背景
我们项目采用了uni-app搭建了一个网站,涉及到一个交互需求,其需求是当用户右键点击一个文本块,出现对应的操作菜单,等同于下面这个交互效果。这个交互效果,拆解来看,就是用户右键的时候,捕获用户当前鼠标点击的x,y坐标,然后弹出操作菜单,操作菜单的位置,就是以用户点击的x,y坐标定位。
开发
遇到这样的需求,一般都先搜索一番,有没有类似的轮子。Vue 原生实现右键菜单组件, 零依赖(vue-contextmenujs), 刚好搜到了这个,有现成的不用白不用。只需要引入,根据api,传递点击的x,y坐标,或者event对象即可完成这个需求,下面是测试代码简单的示例。
<div @contextmenu="handleContextMenu">测试</div>
const handleContextMenu = (event) => {
const { clientX, clientY } = event
this.$contextmenu({
items: [
{ label: "查看网页源代码(V)", icon: "el-icon-view" },
{ label: "检查(N)" }
],
// event 或者直接传入event对象
x: clientX,
y: clientY,
customClass: "custom-class",
zIndex: 3,
minWidth: 230
});
return false;
})
}
遇到的问题
一切都是这么完美,结果测试的时候,发现右键的菜单根本就没有弹出来,第一时间想到是不是api写错了,再赶紧重新对照一下,发现是按照文档写的呢。看来,是不能按时下班了。经过一番调试发现,发现event对象,根本没有clientX和clientY属性,为啥呢没有这个属性呢,是不是uni-app的原因呢,我重新写了一个比较简单的html页面,测试右键事件的event对象,发现两者输出的event并不一致。
应该是uni-app@click, @contextmenu等事件的元素event对象,内部进行统一处理输出的,导致出现的问题。
如何解决
随后我们在,利用uni-app搭建网站中,利用冒泡原理,监听document对象的oncontextmenu事件,
因为在页面的点击右键,会冒泡到document对象上,这样也能获取到用户具体点击的clientX和clientY属性
然后再调用$contextmenu方法,就能成功触发了。最后验证这个方案可行。
document.oncontextmenu = function (e) {
console.log('输出右键事件event', e)
}
但是还没有完,我们还漏了一点,那就是如果当前右键点击的dom, 我并不想展示右键菜单内容,该怎么处理,因为现在我们监听的是document对象只要右键任何元素,都会触发这个事件。想知道这个如何处理,那么请继续向下看。
右键事件event对象,在不同浏览器版本表现是不同
低版本的chrome浏览器,右键的event对象,是属于MouseEvent对象,而在高版本的chrome浏览器,右键的event对象是属于PointEvent对象。这样会导致返回的event对象有些属性输出不一致,例如MouseEvent对象,有path属性,而PointEvent则没有,如果使用到path属性,需要注意兼容性的处理。
例如需要判断点击的元素,能不能有右键的交互,我们可能会给,需要有右键点击功能的dom, 添加一个特殊的class,在document.oncontextmenu监听事件时,判断当前event对象path是否包含这个class那么,如果包含的话就展示右键菜单内容,如果没有的话,即使右键这个dom,也不展示右键菜单内容。但是由于path有兼容性的问题,我们就可以这样处理,给需要右键点击功能dom添加特殊data-xx属性,判断当前点击的event.target.dataset有没有,我们设置的特殊属性,如果有,则展示右键菜单内容,没有则不展示,这个兼容性是我们测试下最好的。
uni-app社区bug描述和修复版本
因为我们的uni-app的版本已经固定了,是2.x版本,怕升级到3.x出现问题,所以只能兼容处理。不采用升级uni-app官方的修复bug之后的版本。
结尾
如有问题,恳请指正。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情