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