摘要:不過也有自己的一套自定義事件方案。可以和事件拿來對比,他們都是用來模擬和執(zhí)行監(jiān)聽的事件。冒泡事件就是就是由內(nèi)向外冒泡的過程,這個(gè)過程不是很復(fù)雜。參考解密事件核心自定義設(shè)計(jì)三解密事件核心模擬事件四本文在上的源碼地址,歡迎來。
歡迎來我的專欄查看系列文章。
以前,我只知道,只有當(dāng)對瀏覽器中的元素進(jìn)行點(diǎn)擊的時(shí)候,才會出發(fā) click 事件,其它的事件也一樣,需要人為的鼠標(biāo)操作。
后來隨著學(xué)習(xí)的不斷深入,才知道原來 JS 可以寫函數(shù)來控制事件的執(zhí)行,這樣子寫代碼才有意思。記得很久很久以前一些惡意網(wǎng)站,明明鼠標(biāo)沒有點(diǎn)擊,卻被網(wǎng)站強(qiáng)行的點(diǎn)擊了某個(gè)鏈接,大概實(shí)現(xiàn)的方式就是這樣的吧。
原生事件其實(shí) JS 的原生事件已經(jīng)做得挺好了,只是 jQuery 將其進(jìn)行封裝,做的更好。
關(guān)于 document.createEvent,下面是一個(gè)簡單的事件點(diǎn)擊的例子:
var fn = function(){ console.log("click"); } var button = document.getElementById("#id"); button.addEventListener("click", fn); // 點(diǎn)擊事件 MouseEvent var myClick = document.createEvent("MouseEvent"); myClick.initMouseEvent("click", false, false, null); // 執(zhí)行 button.dispatchEvent(myClick); // "click"
除了鼠標(biāo)事件,還可以自定義事件:
// 隨便自定義一個(gè)事件 test.click button.addEventListener("test.click", fn); var testEvent = document.createEvent("CustomEvent"); // customEvent 也可以初始化為鼠標(biāo)事件,不一定非要自定義事件 testEvent.initCustomEvent("test.click", false, false, null); button.dispatchEvent(testEvent); // "click"
JS 原生的模擬事件,使用起來還是很方便的,以上便是原生的。
不過 jQuery 也有自己的一套自定義事件方案。
jQuery.triggerjQuery.trigger 可以和 HTMLElement.dispatchEvent 事件拿來對比,他們都是用來模擬和執(zhí)行監(jiān)聽的事件。
如何使用關(guān)于使用,則比較簡單了.trigger():
var $body = $(document.body); // 先綁定事件 $body.on("click", function(){ console.log("click"); }) // 執(zhí)行 $body.trigger("click"); //"click"
trigger 還支持更多的參數(shù),同樣可以自定義事件:
$body.on("click.test", function(e, data1, data2){ console.log(data1 + "-" + data2); }) $body.trigger("click.test", ["hello", "world"]);trigger 源碼
trigger 的源碼有些簡單,因?yàn)檫€是要借助于 jQuery.event 來處理:
jQuery.fn.extend( { trigger: function(type, data){ return this.each(function(){ jQuery.event.trigger(type, data, this); }) }, // triggerHandler 處理第一個(gè)且不觸發(fā)默認(rèn)事件 triggerHandler: function( type, data ) { var elem = this[ 0 ]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } } );
所以 trigger 事件的起點(diǎn)又回到了 jQuery.event。
jQuery.event.trigger其實(shí) trigger 和 add + handler 函數(shù)很類似,大致都是從 data cache 中搜索緩存,執(zhí)行回調(diào)函數(shù)。需要考慮要不要執(zhí)行默認(rèn)事件,即第四個(gè)參數(shù)為 true 的情況。
jQuery.extend(jQuery.event, { // onleyHandlers 表示不考慮冒泡事件 trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; cur = tmp = elem = elem || document; // Don"t do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // 異步不沖突 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(); } ontype = type.indexOf( ":" ) < 0 && "on" + type; // 改裝原生的 event 事件 event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // 判斷是否只執(zhí)行當(dāng)前 trigger 事件,不冒泡 event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join( "." ); event.rnamespace = event.namespace ? new RegExp( "(^|.)" + namespaces.join( ".(?:.*.|)" ) + "(.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // 向 document 冒泡并把冒泡結(jié)果存儲到 eventPath 數(shù)組中 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // 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 ); } } // 按需求來執(zhí)行 i = 0; while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // 從 data cache 中獲得回調(diào)函數(shù) handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { // 執(zhí)行 handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // 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 ) ) { // 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 && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { // Don"t re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, })總結(jié)
在 jQuery.event.trigger 中,比較有意思的是模擬冒泡機(jī)制,大致的思路就是:
把當(dāng)前 elem 存入數(shù)組;
查找當(dāng)前 elem 的父元素,如果符合,push 到數(shù)組中,重復(fù)第一步,否則下一步;
遍歷數(shù)組,從 data cache 中查看是否綁定 type 事件,然后依次執(zhí)行。
冒泡事件就是就是由內(nèi)向外冒泡的過程,這個(gè)過程不是很復(fù)雜。
event 事件應(yīng)該就這么多內(nèi)容吧。
參考解密jQuery事件核心 - 自定義設(shè)計(jì)(三)
MDN createEvent
解密jQuery事件核心 - 模擬事件(四)
本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86831.html
摘要:大潮來襲前端開發(fā)能做些什么去年谷歌和火狐針對提出了的標(biāo)準(zhǔn),顧名思義,即的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的標(biāo)準(zhǔn)讓我們可以使用語言來開發(fā)。 VR 大潮來襲 --- 前端開發(fā)能做些什么 去年谷歌和火狐針對 WebVR 提出了 WebVR API 的標(biāo)準(zhǔn),顧名思義,WebVR 即 web + VR 的體驗(yàn)方式,我們可以戴著頭顯享受沉浸式的網(wǎng)頁,新的 API 標(biāo)準(zhǔn)讓我們可以使用 ...
摘要:專題系列共計(jì)篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究專題之函數(shù)組合專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫一個(gè)函數(shù),輸入,返回。 JavaScript 專題之從零實(shí)現(xiàn) jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實(shí)現(xiàn)一個(gè) jQuery 的 ext...
摘要:原文地址如果您對本系列文章感興趣,歡迎關(guān)注訂閱這里前言本文介紹如何在多項(xiàng)目間共用同一套基礎(chǔ)設(shè)施,又或是某種層次的框架。而以上所述的種種,就構(gòu)成了一套完整的解決方案,也稱基礎(chǔ)設(shè)施。下面就以從到的改造過程來介紹如何實(shí)現(xiàn)多項(xiàng)目共用基礎(chǔ)設(shè)施。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/1190...
摘要:我個(gè)人慣用的是,因此本文以為例來介紹如何打造一個(gè)自定義的。引入全局的方法請看我之前的這篇文章多頁應(yīng)用架構(gòu)系列四老式插件還不能丟,怎么兼容,我的腳手架項(xiàng)目也是使用的這套方案。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/1190000007043716如果您對本系列文章感興趣,歡迎關(guān)注訂閱...
摘要:本文將分享軟件基本用法及文件進(jìn)程注冊表查看,這是一款微軟推薦的系統(tǒng)監(jiān)視工具,功能非常強(qiáng)大可用來檢測惡意軟件。可以幫助使用者對系統(tǒng)中的任何文件注冊表操作進(jìn)行監(jiān)視和記錄,通過注冊表和文件讀寫的變化,有效幫助診斷系統(tǒng)故障或發(fā)現(xiàn)惡意軟件病毒及木馬。 ...
閱讀 1627·2021-11-22 13:53
閱讀 2861·2021-11-15 18:10
閱讀 2767·2021-09-23 11:21
閱讀 2511·2019-08-30 15:55
閱讀 486·2019-08-30 13:02
閱讀 763·2019-08-29 17:22
閱讀 1705·2019-08-29 13:56
閱讀 3462·2019-08-29 11:31