前言
我在之前寫過關於 JS 拖拽的文章,實現方式和網上能搜到的方法大致相同,別無二致,但是在一次偶然的測試中發現,這種綁定事件的方式可能會和其它的拖拽事件產生沖突,由此產生了對於事件綁定的思考。本文主要介紹解決這種沖突的方法,其實就是事件綁定的時機問題。
問題來源
這個問題是在類似如下 CodePen 例子中發現的,在有拖拽功能的頁面中添加一個原生 input range 元素,可以發現 input range 的拖拽失效了。
See the Pen drag with conflict issue by Zongbin (@nzbin) on CodePen.
讓我們看一下拖拽方法代碼:
var draggable = function(modal, handle) { ... $(handle).on('mousedown', dragStart); $(document).on('mousemove', dragMove); $(document).on('mouseup', dragEnd); }
幾乎網上的大部分拖拽案例都是上面這種綁定事件的方法。起初以為是 jQuery 事件綁定的問題,其實完全不相關,使用原生 JS 同樣會遇到這種問題。
再看一下拖拽的事件綁定,很明顯,在 document 上綁定的事件和 input range 的拖拽事件沖突了。其實,document 作為最上層的節點,它上面不應該綁定其它事件(事件代理除外),如果綁定,必須是臨時性綁定,否則一定會造成沖突。
解決方法
知道問題所在之后,解決方法也非常簡單,其中參考了 jQuery UI 的處理方式。
我們可以在拖拽開始的時候綁定 document 的事件,然后在拖拽結束的時候移除 document 的事件。
var draggable = function(modal, handle) { ... var dragStart = function(e) { ... $(document).on('mousemove', dragMove) .on('mouseup', dragEnd); } ... var dragEnd = function(e) { $(document).off('mousemove') .off('mouseup'); ... } $(handle).on('mousedown', dragStart); }
下面 CodePen 中的 input range 已經可以正常拖動了。
See the Pen drag with conflict issue fixed by Zongbin (@nzbin) on CodePen.
總結
我們可以通過控制台的 Event Listener 查看綁定的事件,在平時的工作中,切記不要污染全局的默認事件。一般情況下,工作中並不會遇到本文所說的這一情況,但是如果真的碰到了,需要知道問題的所在。