摘要:而事件委托的概念事件目標自身不處理事件,而是將其委托給父元素或祖先元素或根元素,而借助事件的冒泡性質由內向外來達到最終處理事件。而且一旦出現,局部刷新導致重新綁定事件。函數的用法,代表要移除的事件,表示選擇的,表示事件處理函數。
歡迎來我的專欄查看系列文章。
這次的內容是來介紹關于 jQuery 的事件委托。不過在之前呢有必要先來了解一下 JS 中的事件委托與冒泡,我之前也寫過類似的博客,事件冒泡與捕獲
由 JS 事件引入事件是 JS DOM 中極具活力的內容,你可以隨時監聽 DOM 的變化,并對它們及時的做出反應,如果你不是太懂 JS 中的事件,建議你先去看一些相關介紹的文章,直接看 jQuery 中的事件委托頭會頭大的。
事件的處理順序由兩個環節,一個是捕獲環節,一個是冒泡環節,借用別人的一張圖:
如果把處理也算進的話,整個事件分為三個階段,分別是捕獲階段,目標處理階段和冒泡階段。捕獲階段由外向內尋找 target,冒泡階段由內向外直到根結點。這只是一個事件,當這三個階段中又穿插著更多的事件時,還需要將事件的執行順序考慮進去。
而 jQuery 事件委托的概念:事件目標自身不處理事件,而是將其委托給父元素或祖先元素或根元素,而借助事件的冒泡性質(由內向外)來達到最終處理事件。
jQuery 中的事件優化首先必須要知道,綁定事件越多,瀏覽器內存占用越大,就會間接的影響性能。而且一旦出現 ajax,局部刷新導致重新綁定事件。
使用事件委托可以解決以上帶來的問題,借助事件的冒泡,尤其當一個父元素的子元素過多,而且子元素綁定的事件非常多時,委托事件的作用就體現出來了。
我本人不善于比較 JS 中的性能問題,感興趣的可以去看看這篇文章關于事件委托性能的設計和比較。深入理解-事件委托。
在早期的 jQuery 版本,使用的是 .delegate()、.bind()、.live()等方法來實現事件監聽,當然也包括.click()方法,隨著 jQuery 的發展,像 live 方法已經明確從 jQuery 中刪除,而其余的方法,比如 bind 方法也將在 3.0 之后的版本陸續刪除,取而代之的是 .on()方法。而且剩下的其它方法都是通過 on 方法來間接實現的,如果介紹,只需要看 on 的源碼即可。
on 函數在 jQuery 中的用法也很簡單,.on( events [, selector ] [, data ], handler(eventObject) )events 表示綁定的事件,比如 "click" 或 "click mouseleave",selector 和 data 是可選的,分別表示要綁定事件的元素和要執行的數據,handler 表示事件執行函數。
off 函數的用法 .off( events [, selector ] [, handler ] ),events 代表要移除的事件,selector 表示選擇的 dom,handler 表示事件處理函數。還有更殘暴的比如 .off()不接受任何參數,表示著移除所有 on 綁定的函數。
on off 函數源碼雖然我分析的源碼時 jQuery 3.1.1,但這個時候 bind 和 delegate 函數并沒有從源碼中移除呢,先來看看它們怎么調用 on:
jQuery.fn.extend( { bind: function( types, data, fn ) { return this.on( types, null, data, fn ); }, unbind: function( types, fn ) { return this.off( types, null, fn ); }, delegate: function( selector, types, data, fn ) { return this.on( types, selector, data, fn ); }, undelegate: function( selector, types, fn ) { // ( namespace ) or ( selector, types [, fn] ) return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); } } );
可以看得出來,全都被 on 和 off 這兩個函數來處理了。
jQuery.fn.extend( { on: function (types, selector, data, fn) { // on 又依托于全局的 on 函數 return on(this, types, selector, data, fn); } } ); function on( elem, types, selector, data, fn, one ) { var origFn, type; // 支持 object 的情況 if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } // 一次執行 object 的每一個 for ( type in types ) { on( elem, type, selector, data, types[ type ], one ); } return elem; } // 參數為兩個的情況 if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { // returnFalse 是一個返回 false 的函數 fn = returnFalse; } else if ( !fn ) { return elem; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return elem.each( function() { // 關鍵 jQuery.event.add( this, types, fn, data, selector ); } ); }
是的,你沒有看錯,這個全局的 on 函數,其實只是起到了校正參數的作用,而真正的大頭是:
jQuery.event = { global = {}, add: function(){...}, remove: function(){...}, dispatch: function(){...}, handlers: function(){...}, addProp: function(){...}, fix: function(){...}, special: function(){...} }
off 函數:
jQuery.fn.off = function (types, selector, fn) { var handleObj, type; if (types && types.preventDefault && types.handleObj) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery(types.delegateTarget).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if (typeof types === "object") { // ( types-object [, selector] ) for (type in types) { this.off(type, selector, types[type]); } return this; } if (selector === false || typeof selector === "function") { // ( types [, fn] ) fn = selector; selector = undefined; } if (fn === false) { fn = returnFalse; } return this.each(function() { // 關鍵 jQuery.event.remove(this, types, fn, selector); }); }總結
可見 jQuery 對于參數的放縱導致其處理起來非常復雜,不過對于使用者來說,卻非常大便利。
委托事件也帶來了一些不足,比如一些事件無法冒泡,load、submit 等,會加大管理等復雜,不好模擬用戶觸發事件等。
參考jQuery 2.0.3 源碼分析 事件綁定 - bind/live/delegate/on
深入理解-事件委托
.on()
本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81780.html
摘要:在中渲染樹中的每個節點即是一個渲染器或者渲染器對象。計算的樣式每個渲染器對象代表一個矩形區域通常是和一個節點的盒模型相對應。坐標系統是相對于根渲染器的。根渲染器的定位為和大小即為瀏覽器窗口的可視化部分比如。渲染器作廢其在屏幕上的矩形區域。 原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland。 本系列持續更新中,Github 地址請查閱這里。 ...
摘要:在中渲染樹中的每個節點即是一個渲染器或者渲染器對象。計算的樣式每個渲染器對象代表一個矩形區域通常是和一個節點的盒模型相對應。坐標系統是相對于根渲染器的。根渲染器的定位為和大小即為瀏覽器窗口的可視化部分比如。渲染器作廢其在屏幕上的矩形區域。 原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland。 本系列持續更新中,Github 地址請查閱這里。 ...
摘要:在中渲染樹中的每個節點即是一個渲染器或者渲染器對象。計算的樣式每個渲染器對象代表一個矩形區域通常是和一個節點的盒模型相對應。坐標系統是相對于根渲染器的。根渲染器的定位為和大小即為瀏覽器窗口的可視化部分比如。渲染器作廢其在屏幕上的矩形區域。 原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland。 本系列持續更新中,Github 地址請查閱這里。 ...
摘要:到目前為止,的貢獻者團隊共名成員,多條,可想而知,是一個多么龐大的項目。參考源碼分析整體架構源碼解析讀書筆記第二章構造對象函數詳解本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 決定你走多遠的是基礎,jQuery 源碼分析,向長者膜拜! 我雖然接觸 jQuery 很久了,但也只是局限于表面使用的層次,碰到一些問題,找到 jQuery 的解決辦法,然后使用。顯然,這種做法的...
摘要:而在構造函數中,返回了的實例對象。在中直接返回過的實例,這里的是的真正構造函數最后對外暴露入口時,將字符與對等起來。因此當我們直接使用創建一個對象時,實際上是創建了一個的實例,這里的正真構造函數是原型中的方法。 showImg(https://segmentfault.com/img/remote/1460000008749398); 早幾年學習前端,大家都非常熱衷于研究jQuery源...
閱讀 1260·2021-11-23 09:51
閱讀 1628·2021-11-16 11:45
閱讀 4014·2021-10-09 09:43
閱讀 2682·2021-07-22 16:47
閱讀 944·2019-08-27 10:55
閱讀 3449·2019-08-26 17:40
閱讀 3083·2019-08-26 11:39
閱讀 3228·2019-08-23 18:39