在執(zhí)行事件的時(shí)候,jQuery 會(huì)根據(jù)事件綁定的時(shí)候處理來執(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 元素綁定一個(gè) mousedown 事件,但是在 div 元素上觸發(fā)的時(shí)候,其實(shí)之前還會(huì)先觸發(fā) li、ul、a,3 個(gè)元素的事件,這是因?yàn)槭录际墙壎ǖ乃膫€(gè)事件,3 個(gè)是通過委托到 div 元素上觸發(fā)的,那么這個(gè)委托是如何處理的?
設(shè)計(jì)的思路解析:
委托的實(shí)現(xiàn)說起來很簡(jiǎn)單,我們事件對(duì)象里面不是有一個(gè) target 屬性嗎? target 就指的觸發(fā)的目標(biāo)對(duì)象。
target 的理解:
<ul> <li>點(diǎn)擊執(zhí)行委托鏈</li> </ul>
通過 target 與實(shí)際的事件綁定對(duì)象我們就可以劃分一個(gè)區(qū)域段,通過遞歸獲取每一個(gè)元素的 parentNode 節(jié)點(diǎn),在每一個(gè)節(jié)點(diǎn)層上通過與委托節(jié)點(diǎn)的對(duì)比用來確定是不是委托的事件元素,這個(gè)就是委托的核心思路了
這個(gè)處理 jQuery 交給了 $.event.handlers 方法,就上一個(gè)結(jié)構(gòu)我們 handlers 這樣分解
簡(jiǎn)單來說就是把 target 到根節(jié)點(diǎn) div 通過 node.parentNode 遍歷一遍,然后找到對(duì)應(yīng)的委托元素節(jié)點(diǎn),如果符合就緩存起來用于之后的操作,可以通過 jQuery.event.handlers 方法我們可以獲取類似這種的一組數(shù)據(jù)結(jié)構(gòu)
那么過濾之后的結(jié)構(gòu)就是這樣了:通過 handlerQueue 保存需要的委托隊(duì)列數(shù)據(jù)
從這里我們可以看出 delegate 綁定的事件和普通綁定的事件是如何分開的,對(duì)應(yīng)一個(gè)元素一個(gè) event.type 的事件,處理對(duì)象隊(duì)列在緩存里只有一個(gè),按照冒泡的執(zhí)行順序與元素的從內(nèi)向外遞歸以及 handlers 的排序,所以就處理了,就形成了事件隊(duì)列的委托在前,自身事件在后的順序,這樣也跟瀏覽器事件執(zhí)行的順序一致了。
區(qū)分delegate綁定和普通綁定的方法是:delegate 綁定從隊(duì)列頭部推入,而普通綁定從尾部推入,通過記錄 delegateCount 來劃分,delegate 綁定和普通綁定
我們按照委托的順序遍歷這個(gè)結(jié)構(gòu)
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(); }
因?yàn)榻Y(jié)構(gòu)上來說,同一個(gè) div 上綁定多個(gè)委托元素,那么事件對(duì)象引用就是同樣的,event.isPropagationStopped 引用永遠(yuǎn)是 div 的事件對(duì)象 div,ul與 p 都是共用的,只是在不同的元素上面修改delegateTarget 與 currentTarget,所以在之前重寫的事件對(duì)象就發(fā)揮作用了,如果在一個(gè)元素上調(diào)用了stopPropagation 那么后面的事件自然都不會(huì)觸發(fā)了,因?yàn)?event.isPropagationStopped 會(huì)獲取這個(gè)狀態(tài)。
總的來說 jQuery.event.handlers 做的事情:
請(qǐng)驗(yàn)證,完成請(qǐng)求
由于請(qǐng)求次數(shù)過多,請(qǐng)先驗(yàn)證,完成再次請(qǐng)求
打開微信掃碼自動(dòng)綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報(bào)