今天要说一个很隐晦的东西,一般可能很难碰到,碰到了可能很难解决。就是当我们自己用mousestart,mousemove,mouseup做自定义拖拽效果的时候,如果这个时候配上click就会引发一个拖拽穿透的bug。
点击上面的链接,用鼠标拖住上下拖拽可滚动列表,然后你会发现,如果你的鼠标在某一个具体的列表项上,就会触发查看详情,其实查看详情是click之后才会触发的,但是这里很明显自定义拖拽触发了click。(注:此bug pc上才有,手机端没有)
问题分析
其实这种问题一般情况下是很难遇到的,只会有某些框架里面出现这种bug,那我们看看这种问题到底是如何出现的。
首先自定义拖拽是利用mousestart,mousemove,mouseup三个事件组合形成的,但是mouseup执行之后,click是一定会执行的,是无法避免的,是无法用preventDefault,stopPropagation,stopImmediatePropagation阻止的。本例的demo中就在mouseup之后执行了上述阻止事件传播的方法,但是并没有效果。因为mouse事件和click事件本身就不是一个系列的,因此没有关系,所以当发生拖拽之后,mouseup一定会执行,click也会在mouseup执行后执行。
解决方案
首先我们可以解决最简单的一种,就是不拖拽的情况下触发只是触发click。
按照刚才的说法,mouseup事件后click必定会触发,但是如果没有发生拖拽,也就是没有触发mousemove事件,这种情况比较简单,我们可以用一个变量纪录是否触发mousemove,在mouseup的时候只触发发生拖拽的情况。
还有一种比较复杂的情况,就是在发生了拖拽的情况下如何避免click的触发?这个时候我们用一个定时去控制一个全局变量,让这个变量在200毫秒之后发生改变,因此mouseup之后click很快就触发了,不到200ms,因此可以保证变量还没有发生变化,click事件里面去检测这个变量,如果是变化之前,那么不执行。具体代码如下:
1 //mouseup事件里定时改变一个变量 2 window.mouseup_click_debug = true; 3 setTimeout(function() { 4 window.mouseup_click_debug = false; 5 }, 200); 6 //click事件里去检测这个变量是否发生改变,如果没改变,说明mouseup刚执行完,这里不执行 7 if(window.mouseup_click_debug) { 8 return false; 9 }
解决后的demo如下:
解决后demo:mouseup模拟drag与click事件冲突(二维码)
转自:http://www.qiutianaimeili.com/html/page/2018/09/5c9jxp7u6ng.html