問題
今天同事(妹子)遇到一個 Zepto
的事件委託的問題來問我,我當時也懵了,後來解決了。問題還是比較坑的,拿出來分享一下。先看看是什麼問題:
自己解決
為什麼?!為什麼事件委託在 .a
上可是卻也觸發了 .b
上的委託。看著妹子求知的眼神,我胸中一陣氣短。猜想著是 .a
委託事件最後換了 class
,DOM立刻更改了,就在 .a
事件後觸發了 .b
。所以我立刻讓她這樣改一下就可以延緩DOM更改:
1 2 3 4 5 6 7 8 9 |
$doc.on('click','.a',function(){ alert('a事件') var $this = $(this) ; setTimeout(function(){ $this.removeClass('a') .addClass('b') },30) }) |
然後就正常了 頁面2。
刨根問底
雖然妹子對我一陣讚許,可是我心裡還是隱隱不安,回來通過諮詢大牛和看原始碼知道了這是什麼原因。
先看看這個頁面 頁面3
檢視原始碼我們可以看到,頁面3 和 頁面1 幾乎一模一樣,就是在 .a
和 .b
的事件委託順序不一樣:
那為什麼 頁面3 就可以正常呢?就是因為 Zepto 的事件委託和我們想象中的事件委託是不一樣的。
Zepto
的事件委託是:
在程式碼解析的時候,所有document的所有
click
委託事件都依次放入一個佇列裡,click 的時候先看當前元素是不是.a
,符合就執行,然後檢視是不是.b
,符合就執行。
這樣的話,就導致如果 .a
的事件在前面,會先執行 .a
事件,然後 class
更改成 b
,Zepto
再檢視當前元素是不是 .b
,以此類推。
這就是 頁面1 出現BUG的原因,而 頁面2 之所以也能解決這個問題是因為 class
變化實在延遲之後,click 事件當時沒有檢測到 .b
。
看看 Zepto 的事件部分是怎麼寫的。可以看到是用$this.each
迴圈繫結在 $this
上的事件。對應在我們的例子,就是 document
上繫結的事件都被塞進一個佇列中。
再看看 jQuery
的事件委託:
document上委託了2個 click 事件,click 後判斷是否當前符合條件(選擇符),然後把事件拿出來執行。
這是符合我們一般的認知的,也是那個妹子那樣寫程式碼的原因。你不妨把頁面1的 Zepto
換成 jQuery
看看。
這是一個 Zepto
和 jQuery
不同的地方,以後要注意了。
>
我的部落格,歡迎訂閱