摘要:十的觸發機制被點擊了元素本身綁定了一個事件,但是是原生事件,它是靠綁定來觸發事件的。
前言:
最重要的還是最后的流程圖,可以試著根據流程圖手寫實現$().on(),下篇文章會放出模擬實現的代碼。
一、舉例
這是A$("#A").on("click" ,function (event) { console.log(event,"A被點擊了") }) $("#A").on("click" ,"#C",function (event) { console.log(event,"點擊了C,即C委托A的click事件被點擊了") })這是C
二、$().on()
(1)進行參數的調整
(2)調用jQuery.event.add()方法
三、jQuery.event.add()最終調用elem.addEventListener()來綁定事件
注意:
(1)綁定常用的事件(如:click、focus),使用handleObj保存
handleObj = jQuery.extend( { //click,mouseout... type: type, //click,mouseout... origType: origType, data: data, //事件處理函數,如 function(){console.log("aaaa")} handler: handler, //索引,用于關聯元素和事件 guid: handler.guid, //事件委托的標志,也是委托的對象選擇器 selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), //命名空間,同一click事件有兩個事件處理程序handler的話, //用這個標識,方便刪除或添加handler namespace: namespaces.join( "." ) }, handleObjIn );
(2)如果綁定的是自定義事件(如:windowResize),則使用handleObjIn保存
if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; }
(1)、(2)都會初始化事件處理器(addEventListener):
//第一次綁定事件,走這里 // Init the event handler queue if we"re the first if ( !( handlers = events[ type ] ) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { //目標元素有addEventListener的話,調用綁定click事件 //eventHandle就綁定到addEventListener上 if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle ); } } }
四、jQuery的事件綁定為何不直接綁定在目標元素身上,而是元素和事件分離?
打印$("#A")
console.log($("#A"),"aaaaaa46")
不要在意jQueryId不同的問題,每次刷新網頁它都會變化
可以看到
jQuery的事件和觸發事件的handler是分離的,
事件集合 存在 事件緩存dataPriv的events上,
//獲取數據緩存 elemData = dataPriv.get( elem );
而handler是由jQuery.event.dispatch()處理
elemData.handle = function( e ) { jQuery.event.dispatch.apply( elem, arguments ) }
為什么要分離?因為元素如果綁定click事件一百次,很耗內存。所以需要將這一百個同類型的事件保存到一個click事件集合中,然后在這一大個click事件集合內,根據guid來執行某一次的click處理代碼
同一事件的處理:
$("body").on("click", "#one", function(e) { show("委托到one觸發") }) $("body").on("click", "#two", function(e) { show("委托到two觸發") })
events是jQuery內部的事件隊列
handle是真正綁定到element上的事件處理函數
body:{ events:{ click:[ 0:{ guid: 1, data: undefined, namespace: "", origType: "click", //事件委托的標志 selector: "#one", type: "click", handler: function(){xxx}, } 1:{ guid: 2, data: undefined, namespace: "", origType: "click", //事件委托的標志 selector: "#two", type: "click", handler: function(){xxx}, } ] }, handle: function(){ jQuery.event.dispatch.apply( elem, arguments ) } }
可以看到,針對同一類型的事件(如click),重復綁定不會再創建新的內存(new Object會有新內存),而是在events里添加新的綁定事件。
記得看第十一點!
五、guid的作用?
添加guid的目的是因為handler沒有直接跟元素節點發生關聯,所以需要一個索引來尋找或者刪除handler
六、命名空間namespace的作用?
$("#one").on("click.one",function () { console.log("one被點擊了") }) $("#one").on("click.two",function () { console.log("two被點擊了") })
命名空間為:
#one:{ events:{ click:[ 0:{ namespace: "one", handler: function(){console.log("one被點擊了")}, } 1:{ namespace: "two", handler: function(){xxx}, } ] }, }
利用命名空間刪除事件:
$("#one").off("click.one")
七、jQuery.event.special 的處理機制
綁定的事件,有些是不能統一處理的,比如load事件,是不支持冒泡的,所以即使開發者未用event.stopPropagation,jQuery也要阻止其冒泡:
jQuery.event ={ special: { load: { // Prevent triggered image.load events from bubbling to window.load //阻止冒泡 noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { }, delegateType: "focusin" }, } }
八、外部是Event,內部是數據緩存events,兩者是不一樣的
外部Event:
$().on("click","#B",function(event){ console.log("A被點擊了") }) //click的event就是jQuery.Event jQuery.Event{ handleObj{ data:undefined, guid: 2, handler:function(){console.log("A被點擊了")}, namespace: "clickA", origType: "click", selector: "#B", type: "click.clickA", }, originalEvent:{ //就是MouseEvent }, target:div#B, type: "click", delegateTarget: div#A, //fix 的標志 jQuery331087940272164138: true, currentTarget: div#A, isDefaultPrevented:xxx, timeStamp:Date.now(), isDefaultPrevented:function(){return false} }
內部緩存events:
let events = dataPriv.get( this, "events" ) events[ delegantCount:1, { data:undefined, guid: 2, handler:function(){console.log("B委托A被點擊了")}, namespace: "clickA", origType: "click", selector: "#B", type: "click.clickA", }, { data:undefined, guid: 1, handler:function(){console.log("A被點擊了")}, namespace: "", origType: "click", selector: undefined, type: "click", } ]
九、為什么要使用fix()來重構 js 的原生 MouseEvent 對象呢?
(1)jQuery 有自己的一套event處理機制,所以需要符合jQuery的event對象
(2)可以傳遞 data 數據,即用戶自定義的數據。
十、trigger的觸發機制
$("#A").on("click" ,function (event) { console.log(event,"A被點擊了") })
元素#A本身綁定了一個click事件,但是click是原生事件,它是靠 addEventListener綁定來觸發事件的。
但是!jQuery的trigger是能夠無差別模擬這個交互行為的
$("#A").trigger("click")
從trigger()的功能上就可以解釋 為什么jQuery要設計元素與數據分離了:
如果是直接綁定的話就無法通過trigger的機制去觸發click事件,
正是因為jQuery沒有直接把事件相關的handler與元素直接綁定,而是采用了分離處理,
所以我們通過trigger觸發click事件與addEventListener觸發click事件的處理流程是一致的,不同的只是觸發的方式而已。
但是,通trigger觸發的事件是沒有事件對象(event)、冒泡(bubble)這些特性的,所以我們需要有一個功能 能模擬出事件對象,然后生成一個遍歷樹(eventPath)模擬出冒泡行為,這個就交給了trigger方法了
關于$().trigger()的源碼解析請看:jQuery源碼解析之trigger()
最后,附上自己做的 jQuery事件綁定到觸發全過程的流程圖:
(完)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104792.html
摘要:階段二目標瀏覽器找到監聽器后,就運行該監聽器階段三冒泡目標到祖在事件自下而上到達目標節點的過程中,瀏覽器會檢測不是針對該事件的監聽器用來捕獲事件,并運行非捕獲事件的監聽器。注意下這種情況,是在里的具體實現,即調用一次后,就執行,卸載事件。 showImg(https://segmentfault.com/img/remote/1460000019304809); 前言:這篇依舊長,請耐...
摘要:通過管理組件通信通過驅動視圖比較差異進行更新操作作者第七頁鏈接來源知乎著作權歸作者所有,轉載請聯系作者獲得授權。達到無刷新的效果。對象的狀態不受外界影響。對象代表一個異步操作,有三種狀態進行中已完成,又稱和已失敗。 以下問題解釋非本人原創,是根據面試經驗整理后覺得更容易理解的解釋版本,歡迎補充。 一. 輸入url后的加載過程 從輸入 URL 到頁面加載完成的過程中都發生了什么 計算機...
摘要:通過管理組件通信通過驅動視圖比較差異進行更新操作作者第七頁鏈接來源知乎著作權歸作者所有,轉載請聯系作者獲得授權。達到無刷新的效果。對象的狀態不受外界影響。對象代表一個異步操作,有三種狀態進行中已完成,又稱和已失敗。 以下問題解釋非本人原創,是根據面試經驗整理后覺得更容易理解的解釋版本,歡迎補充。 一. 輸入url后的加載過程 從輸入 URL 到頁面加載完成的過程中都發生了什么 計算機...
摘要:通過管理組件通信通過驅動視圖比較差異進行更新操作作者第七頁鏈接來源知乎著作權歸作者所有,轉載請聯系作者獲得授權。達到無刷新的效果。對象的狀態不受外界影響。對象代表一個異步操作,有三種狀態進行中已完成,又稱和已失敗。 以下問題解釋非本人原創,是根據面試經驗整理后覺得更容易理解的解釋版本,歡迎補充。 一. 輸入url后的加載過程 從輸入 URL 到頁面加載完成的過程中都發生了什么 計算機...
閱讀 1459·2021-10-18 13:29
閱讀 2684·2021-10-12 10:18
閱讀 3580·2021-09-22 15:06
閱讀 2596·2019-08-29 17:09
閱讀 2787·2019-08-29 16:41
閱讀 1493·2019-08-29 13:48
閱讀 3226·2019-08-26 13:49
閱讀 3325·2019-08-26 13:34