JS - 解决鼠标单击、双击事件冲突问题(原生js实现)
首先,来了解一下点击事件发生的先后顺序:
单击:mousedown, mouseup, click
双击:mousedown, mouseup, click, mousedown, mouseup, click, dblclick
由于鼠标双击时每一次触发双击事件都会引起两次单击事件和一次双击事件,原生的js不提供专门的双击事件。
因为业务原因,双击和单机都绑定了不同的业务,在双击的时候又触发了单机,影响了页面的正常显示
出现问题的代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script type="text/javascript"> /* * 页面初始化 */ function onload() { document.addEventListener('click', onDocumentClick); document.addEventListener('dblclick', onDocumenDblClick); } /* * 鼠标单击事件响应 * event 鼠标事件对象 */ function onDocumentClick(event) { console.log("鼠标单击"); } /* * 鼠标双击事件响应 * event 鼠标事件对象 */ function onDocumenDblClick(event) { console.log("鼠标双击"); } </script> </head> <body onload="onload()"> </body> </html>
解决办法:
setTimerout
所以双击时为了屏蔽单击事件,引入定时器功能,动态的为每次鼠标单击计时,300ms,300ms内鼠标再次点击会出发双击事件而不走单击事件
解决代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script type="text/javascript"> //单击延时触发 var clickTimeId; /* * 页面初始化 */ function onload() { document.addEventListener('click', onDocumentClick); document.addEventListener('dblclick', onDocumenDblClick); } /* * 鼠标单击事件响应 * event 鼠标事件对象 */ function onDocumentClick(event) { // 取消上次延时未执行的方法 clearTimeout(clickTimeId); //执行延时 clickTimeId = setTimeout(function() { //此处为单击事件要执行的代码 console.log("鼠标单击"); }, 250); } /* * 鼠标双击事件响应 * event 鼠标事件对象 */ function onDocumenDblClick(event) { // 取消上次延时未执行的方法 clearTimeout(clickTimeId); console.log("鼠标双击"); } </script> </head> <body onload="onload()"> </body> </html>
如果还vue 同样的方法,但是注意有可能会有一些版本不支持,1.0版本是可以,2.0的在线的版本有一些不支持native,到官网中在线引入vue(2019年10月15日)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试单击双击</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <style> #box{ background-color:pink } </style> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> window.onload=function(){ //var clickTimeId; new Vue({ el:'#box', data:{ clickTimeId:"", }, methods:{ onDocumentClick(event) { // 取消上次延时未执行的方法 clearTimeout(this.clickTimeId); //执行延时 this.clickTimeId = setTimeout(function() { //此处为单击事件要执行的代码 console.log("0"); }, 250); }, onDocumenDblClick(event) { // 取消上次延时未执行的方法 clearTimeout(this.clickTimeId); console.log("1"); } } }); }; </script> </head> <body> <button id="box" @click="onDocumentClick" @dblclick="onDocumenDblClick"> 点我啊 </button> </body> </html>
在实际使用过程中还发现了一个有趣的应用,我们知道没有设置定时器的时候,双击的时候是触发两次click的事件,如果设置 定时的时间低于170ms的时候 双击时会触发一次单击的事件 如果有特殊需要也可以控制好定时器的时间
2020年2月15号
在实际组态项目中的时候,因为特殊情况,还是有时间冲突的问题,添加了定时器就导致了页面的其他业务不能正常使用了,所以最后还是放弃了定时器这种做法
最终的解决办法:
在单击的时候记录下鼠标的xy位置,然后双击的结束的时候记录此时鼠标的xy位置,通过两次的xy位置进行对比,如果两次的xy位置相同,或者在一个允许很小的范围,就证明是双击了,其他就当做是单击处理,这样一来的问题就都解决,这种方法推荐,亲测可试