在執(zhí)行事件的時候,jQuery 會根據(jù)事件綁定的時候處理來執(zhí)行事件的逐漸觸發(fā),我們觀察一組代碼:
div.on('mousedown', 'li', function(e) { show('委托到li觸發(fā)') }) div.on('mousedown', 'ul', function(e) { show('委托到ul觸發(fā)') }) div.on('mousedown', 'a', function(e) { show('委托到a觸發(fā)') }) div.on('mousedown', function(e) { show('mousedown') })
給 div 元素綁定一個 mousedown 事件,但是在 div 元素上觸發(fā)的時候,其實之前還會先觸發(fā) li、ul、a,3 個元素的事件,這是因為事件都是綁定的四個事件,3 個是通過委托到 div 元素上觸發(fā)的,那么這個委托是如何處理的?
設計的思路解析:
委托的實現(xiàn)說起來很簡單,我們事件對象里面不是有一個 target 屬性嗎? target 就指的觸發(fā)的目標對象。
target 的理解:
<ul> <li>點擊執(zhí)行委托鏈</li> </ul>
通過 target 與實際的事件綁定對象我們就可以劃分一個區(qū)域段,通過遞歸獲取每一個元素的 parentNode 節(jié)點,在每一個節(jié)點層上通過與委托節(jié)點的對比用來確定是不是委托的事件元素,這個就是委托的核心思路了
這個處理 jQuery 交給了 $.event.handlers 方法,就上一個結構我們 handlers 這樣分解
簡單來說就是把 target 到根節(jié)點 div 通過 node.parentNode 遍歷一遍,然后找到對應的委托元素節(jié)點,如果符合就緩存起來用于之后的操作,可以通過 jQuery.event.handlers 方法我們可以獲取類似這種的一組數(shù)據(jù)結構
那么過濾之后的結構就是這樣了:通過 handlerQueue 保存需要的委托隊列數(shù)據(jù)
從這里我們可以看出 delegate 綁定的事件和普通綁定的事件是如何分開的,對應一個元素一個 event.type 的事件,處理對象隊列在緩存里只有一個,按照冒泡的執(zhí)行順序與元素的從內向外遞歸以及 handlers 的排序,所以就處理了,就形成了事件隊列的委托在前,自身事件在后的順序,這樣也跟瀏覽器事件執(zhí)行的順序一致了。
區(qū)分delegate綁定和普通綁定的方法是:delegate 綁定從隊列頭部推入,而普通綁定從尾部推入,通過記錄 delegateCount 來劃分,delegate 綁定和普通綁定
我們按照委托的順序遍歷這個結構
while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) { event.currentTarget = matched.elem; j = 0; while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) { ret = handleObj.handler.apply(matched.elem, args); //如果返回了false if (ret !== undefined) { if ((event.result = ret) === false) { event.preventDefault(); event.stopPropagation(); }
因為結構上來說,同一個 div 上綁定多個委托元素,那么事件對象引用就是同樣的,event.isPropagationStopped 引用永遠是 div 的事件對象 div,ul與 p 都是共用的,只是在不同的元素上面修改delegateTarget 與 currentTarget,所以在之前重寫的事件對象就發(fā)揮作用了,如果在一個元素上調用了stopPropagation 那么后面的事件自然都不會觸發(fā)了,因為 event.isPropagationStopped 會獲取這個狀態(tài)。
總的來說 jQuery.event.handlers 做的事情:
請驗證,完成請求
由于請求次數(shù)過多,請先驗證,完成再次請求
打開微信掃碼自動綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報