摘要:一和的作用和區(qū)別觸發(fā)被選元素上的指定事件以及事件的默認行為比如表單提交不會引起事件比如表單提交的默認行為觸發(fā)所有匹配元素的指定事件只觸發(fā)第一個匹配元素的指定事件會冒泡不會冒泡二被點擊了作用看一源碼觸發(fā)事件,是自定義事件的額外參數(shù)源碼行解析本
一、$().trigger()和$().triggerHandler() 的作用和區(qū)別
(1)trigger("focus") 觸發(fā)被選元素上的指定事件(focus)以及事件的默認行為(比如表單提交);
triggerHandler(xxx) 不會引起事件(比如表單提交)的默認行為
(2)trigger(xxx) 觸發(fā)所有匹配元素的指定事件;
triggerHandler(xxx) 只觸發(fā)第一個匹配元素的指定事件
(3)trigger(xxx) 會冒泡;
triggerHandler(xxx) 不會冒泡
二、$().trigger()
$("#one").on("click",function () { console.log("one被點擊了") }) $("#one").trigger("click")
作用:
看 一、(1)
源碼:
//觸發(fā)type事件,data是自定義事件的額外參數(shù) //源碼9014行 trigger: function( type, data ) { return this.each( function() { jQuery.event.trigger( type, data, this ); } ); },
解析:
本質(zhì)是調(diào)用的jQuery.event.trigger()方法
三、jQuery.event.trigger()
源碼:
//源碼8850行 //type, data, this trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, //冒泡路徑數(shù)組 eventPath = [ elem || document ], //判斷event是否有"type"屬性,有則取event.type,沒有則取event type = hasOwn.call( event, "type" ) ? event.type : event, //同上 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; //當前元素 cur = lastElement = tmp = elem = elem || document; //文本內(nèi)容或者是注釋則不觸發(fā)事件 // Don"t do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } //由focus/blur轉(zhuǎn)變到focusin/out,現(xiàn)在不觸發(fā)focus/blur事件 // focus/blur morphs to focusin/out; ensure we"re not firing them right now //rfocusMorph:focusin focus|focusout blur if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } //可以不看 if ( type.indexOf( "." ) > -1 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split( "." ); type = namespaces.shift(); namespaces.sort(); } //onclick,onfocus等等 ontype = type.indexOf( ":" ) < 0 && "on" + type; //event一般是字符串,所以一般是undefined //獲取對應(yīng)type類型的jQuery.event // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : //click,false new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) //onlyHandlers一般為undefined //3 event.isTrigger = onlyHandlers ? 2 : 3; //"" event.namespace = namespaces.join( "." ); //null event.rnamespace = event.namespace ? new RegExp( "(^|.)" + namespaces.join( ".(?:.*.|)" ) + "(.|$)" ) : null; //清空event以防它被復用 // Clean up the event in case it is being reused event.result = undefined; //target屬性為目標DOM元素 //我們一般取的e.target.value,也正是目標元素的值 if ( !event.target ) { event.target = elem; } //復制data并預(yù)先考慮event,創(chuàng)建handler集合 // Clone any incoming data and prepend the event, creating the handler arg list //簡單點,就是 data=[event] data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); //賦值有需要特殊處理的type // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } //提前確定事件冒泡的路徑 // Determine event propagation path in advance, per W3C events spec (#9951) //冒泡至document,再到window;關(guān)注全局的ownerDocument // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { //click bubbleType = special.delegateType || type; //clickclick //如果不是focus/blur的話,獲取它的父元素 if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } //for循環(huán)的語法(a; b; c) //a在單次循環(huán)開始前執(zhí)行 //b是單次循環(huán)的條件(這里即cur存在) //c是單次循環(huán)結(jié)束后執(zhí)行 for ( ; cur; cur = cur.parentNode ) { console.log(cur,"cur8967") //將目標元素的祖先元素都push進數(shù)組 eventPath.push( cur ); tmp = cur; } //只有當tmp是document時,將window加上 // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } //觸發(fā)冒泡機制 // Fire handlers on the event path i = 0; //e.stopPropagation()這是阻止冒泡的方法 //isPropagationStopped() 檢查是否阻止冒泡了,返回boolean while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { lastElement = cur; event.type = i > 1 ? bubbleType : special.bindType || type; console.log(i,"lastElement8987") // jQuery handler //( dataPriv.get( cur, "events" ) || {} )[ event.type ] // 先判斷cur元素的events是否有綁定click //dataPriv.get( cur, "handle" ) //再獲取cur元素的click事件處理程序 //獲取目標元素的觸發(fā)事件的事件處理程序 handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && //獲取觸發(fā)事件的處理程序 dataPriv.get( cur, "handle" ); /*讓冒泡元素執(zhí)行handle,這行代碼是觸發(fā)冒泡機制的關(guān)鍵*/ /*在執(zhí)行click事件的處理程序后,自然就會執(zhí)行e.stopPropagation(), * 從而讓event.isPropagationStopped()=true*/ if ( handle ) { handle.apply( cur, data ); } //接下來處理原生的事件及處理程序 //click為onclick // Native handler handle = ontype && cur[ ontype ]; //如果有綁定原生onclick事件的話 if ( handle && handle.apply && acceptData( cur ) ) { //執(zhí)行onclick事件的處理程序 event.result = handle.apply( cur, data ); if ( event.result === false ) { //阻止元素的默認行為(如提交表單submit) event.preventDefault(); } } } event.type = type; //如果沒有人阻止默認行為的話,現(xiàn)在就阻止 /*比如觸發(fā)的click事件,但不會跳轉(zhuǎn)*/ // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( ( !special._default || special._default.apply( eventPath.pop(), data ) === false ) && acceptData( elem ) ) { //在目標上,用重復的命名調(diào)用原生DOM事件,會在window層面上影響其他元素 // Call a native DOM method on the target with the same name as the event. // Don"t do default actions on window, that"s where global variables be (#6170) if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { //當我們觸發(fā)FOO事件(如click)時,不要重復觸發(fā)它的onFOO(onclick)事件 // Don"t re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; //將jQuery對象的onclick屬性置為null //比如就不會去跳轉(zhuǎn)了 if ( tmp ) { elem[ ontype ] = null; } //阻止重復觸發(fā)同樣的事件,因為我們已經(jīng)把它冒泡了 // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; //如果已經(jīng)執(zhí)行阻止冒泡了,則為window添加阻止冒泡的監(jiān)聽 if ( event.isPropagationStopped() ) { lastElement.addEventListener( type, stopPropagationCallback ); } console.log(elem[ type ],"type9053") //執(zhí)行type事件 elem[ type ](); if ( event.isPropagationStopped() ) { lastElement.removeEventListener( type, stopPropagationCallback ); } jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; },
解析:
(1)trigger()的冒泡機制的實現(xiàn)
在if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) )中,通過eventPath存儲目標元素的祖先元素:
//clickclick //如果不是focus/blur的話,獲取它的父元素 if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } //for循環(huán)的語法(a; b; c) //a在單次循環(huán)開始前執(zhí)行 //b是單次循環(huán)的條件(這里即cur存在) //c是單次循環(huán)結(jié)束后執(zhí)行 for ( ; cur; cur = cur.parentNode ) { console.log(cur,"cur8967") //將目標元素的祖先元素都push進數(shù)組 eventPath.push( cur ); tmp = cur; } //只有當tmp是document時,將window加上 // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); }
通過eventPath.push(cur. parentNode)將冒泡元素裝進數(shù)組中,并通過while循環(huán)觸發(fā)冒泡機制:
//觸發(fā)冒泡機制 // Fire handlers on the event path i = 0; //e.stopPropagation()這是阻止冒泡的方法 //isPropagationStopped() 檢查是否阻止冒泡了,返回boolean while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { lastElement = cur; event.type = i > 1 ? bubbleType : special.bindType || type; console.log(i,"lastElement8987") // jQuery handler //( dataPriv.get( cur, "events" ) || {} )[ event.type ] // 先判斷cur元素的events是否有綁定click //dataPriv.get( cur, "handle" ) //再獲取cur元素的click事件處理程序 //獲取目標元素的觸發(fā)事件的事件處理程序 handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && //獲取觸發(fā)事件的處理程序 dataPriv.get( cur, "handle" ); /*讓冒泡元素執(zhí)行handle,這行代碼是觸發(fā)冒泡機制的關(guān)鍵*/ /*在執(zhí)行click事件的處理程序后,自然就會執(zhí)行e.stopPropagation(), * 從而讓event.isPropagationStopped()=true*/ if ( handle ) { handle.apply( cur, data ); } //接下來處理原生的事件及處理程序 //click為onclick // Native handler handle = ontype && cur[ ontype ]; //如果有綁定原生onclick事件的話 if ( handle && handle.apply && acceptData( cur ) ) { //執(zhí)行onclick事件的處理程序 event.result = handle.apply( cur, data ); if ( event.result === false ) { //阻止元素的默認行為(如提交表單submit) event.preventDefault(); } } }
關(guān)鍵代碼是handle.apply( cur, data ),它用來執(zhí)行cur元素的事件的處理程序。
(2)通過e.stopPropagation()來阻止冒泡的原理:
這是one
① 上面這段代碼會先執(zhí)行$("#one").trigger("click")
② trigger()里會執(zhí)行到上面(1)的handle.apply( cur, data );,而handle會執(zhí)行$("#one")的click事件的處理程序:
e.stopPropagation() console.log("one被點擊了")
③ e.stopPropagation()走的是這里:
//event的屬性賦值 //源碼5749行 jQuery.Event.prototype = { constructor: jQuery.Event, //xxx isPropagationStopped: returnFalse, //false //xxx //xxx //當執(zhí)行e.stopPropagation()后走這邊 //源碼5767行 stopPropagation: function() { var e = this.originalEvent; //isPropagationStopped方法返回true this.isPropagationStopped = returnTrue; if ( e && !this.isSimulated ) { e.stopPropagation(); } }, }
最后讓isPropagationStopped()方法返回true
④ 注意:$().trigger()里的event也就是click里的event,所以會影響到while循環(huán)地判斷,從而達到阻止冒泡循環(huán)的 目的
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { }
⑤ 為什么說click里的event是$().trigger()里的event?
//event一般是字符串,所以一般是undefined //獲取對應(yīng)type類型的jQuery.event // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : //click,false new jQuery.Event( type, typeof event === "object" && event );
因為 event 是根據(jù)type(click)類型生成的,所以trigger里的event的部分屬性和click的event屬性相同。
(3)原生js綁定的事件的執(zhí)行,如onclick
$("#one").click(function(e){ console.log("one被點擊了") }) document.getElementById("one").onclick=function(){ console.log("onclick被點擊了") }
還是在while循環(huán)中:
//接下來處理原生的事件及處理程序 //click為onclick // Native handler handle = ontype && cur[ ontype ]; //如果有綁定原生onclick事件的話 if ( handle && handle.apply && acceptData( cur ) ) { //執(zhí)行onclick事件的處理程序 event.result = handle.apply( cur, data ); if ( event.result === false ) { //阻止元素的默認行為(如提交表單submit) event.preventDefault(); } }
也就是說:
在冒泡循環(huán)機制中,在執(zhí)行完jQuery綁定的handler后,會接著執(zhí)行原生JS 綁定的handler!
(4)rfocusMorph
//匹配focusinfocus或者focusoutblur //源碼8872行 var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
(5)jQuery.makeArray()
作用:
用于將一個類似數(shù)組的對象轉(zhuǎn)換為真正的數(shù)組對象
注意:
類數(shù)組對象具有許多數(shù)組的屬性(例如length屬性,[]數(shù)組訪問運算符等),不過它畢竟不是數(shù)組,缺少從數(shù)組的原型對象上繼承下來的內(nèi)置方法(例如:pop()、reverse()等)。
源碼:
//結(jié)果僅供內(nèi)部使用 // results is for internal usage only //源碼442行 makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { //Object()等效于new Object() //先將arr轉(zhuǎn)為對象類型,因為js中的array是Object if ( isArrayLike( Object( arr ) ) ) { //將second合并到first后面 jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { //ret.push(arr) push.call( ret, arr ); } } //返回array return ret; },
① $.isArrayLike
作用:
判斷是不是類數(shù)組
源碼:
//判斷是不是類數(shù)組 //源碼561行 function isArrayLike( obj ) { // Support: real iOS 8.2 only (not reproducible in simulator) // `in` check used to prevent JIT error (gh-2145) // hasOwn isn"t used here due to false negatives // regarding Nodelist length in IE //后兩個是兼容性考慮的判斷 var length = !!obj && "length" in obj && obj.length, //obj類型 type = toType( obj ); if ( isFunction( obj ) || isWindow( obj ) ) { return false; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj; }
(6)最后一個if,觸發(fā)trigger()時,阻止jQuery元素的默認行為
if ( !onlyHandlers && !event.isDefaultPrevented() ){ xxx xxx }
綜上,trigger一共做了三件事:
(1)觸發(fā)冒泡機制
(2)觸發(fā)原生綁定事件
(3)阻止元素默認行為
最后,附上自己整理的觸發(fā) trigger() 的流程圖:
(完)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/104382.html
摘要:階段二目標瀏覽器找到監(jiān)聽器后,就運行該監(jiān)聽器階段三冒泡目標到祖在事件自下而上到達目標節(jié)點的過程中,瀏覽器會檢測不是針對該事件的監(jiān)聽器用來捕獲事件,并運行非捕獲事件的監(jiān)聽器。注意下這種情況,是在里的具體實現(xiàn),即調(diào)用一次后,就執(zhí)行,卸載事件。 showImg(https://segmentfault.com/img/remote/1460000019304809); 前言:這篇依舊長,請耐...
摘要:十的觸發(fā)機制被點擊了元素本身綁定了一個事件,但是是原生事件,它是靠綁定來觸發(fā)事件的。 showImg(https://segmentfault.com/img/remote/1460000019505402); 前言:最重要的還是最后的流程圖,可以試著根據(jù)流程圖手寫實現(xiàn)$().on(),下篇文章會放出模擬實現(xiàn)的代碼。 一、舉例 這是A 這是C ...
摘要:一起源方法最終是用綁定事件的而方法正是等于二作用觸發(fā)綁定的事件的處理程序源碼源碼行即原生觸發(fā)事件的處理程序修正對象獲取事件的處理程序集合,結(jié)構(gòu)如下從數(shù)據(jù)緩存中獲取事件處理集合即目標元素委托目標這段代碼壓根不會執(zhí)行,因為全局搜索沒找到結(jié)構(gòu) showImg(https://segmentfault.com/img/remote/1460000019464031); 一、起源jQuery.e...
閱讀 2465·2021-09-09 09:33
閱讀 2865·2019-08-30 15:56
閱讀 3119·2019-08-30 14:21
閱讀 891·2019-08-30 13:01
閱讀 855·2019-08-26 18:27
閱讀 3584·2019-08-26 13:47
閱讀 3449·2019-08-26 10:26
閱讀 1583·2019-08-23 18:38