今天要說一個很隱晦的東西,一般可能很難碰到,碰到了可能很難解決。就是當我們自己用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