jQuery 源碼分析(十七) 事件系統模塊 實例方法和便捷方法 詳解

来源:https://www.cnblogs.com/greatdesert/archive/2019/10/30/11679507.html
-Advertisement-
Play Games

實例方法和便捷方法是指jQuery可以直接通過鏈接操作的方法,是通過調用$.event上的方法(上一節介紹的底層方法)來實現的,常用的如下: on(types,selector,data,fn,one) ;為匹配元素集合中的每個元素綁定一個或多個類型的事件監聽函數 types ;事件類型字元串,多個 ...


實例方法和便捷方法是指jQuery可以直接通過鏈接操作的方法,是通過調用$.event上的方法(上一節介紹的底層方法)來實現的,常用的如下:

  • on(types,selector,data,fn,one)  ;為匹配元素集合中的每個元素綁定一個或多個類型的事件監聽函數
    • types          ;事件類型字元串,多個事件類型之間用空格隔開
    • selector      ;可選,是一個選擇器表達式字元串,用於綁定代理事件。
    • data            ;傳遞給事件監聽函數的自定義數據,可以是任何類型。
    • fn           ;待綁定的監聽函數
    • one                  ;該事件是否只執行一次,為方法.one()提供支持

     writer by:大沙漠 QQ:22969969

  • off(types,selector,fn)  ;移除匹配元素中每個元素上綁定的一個或多個類型的監聽函數,參數如下:
    • types               ;一個或多個以空格分隔的事件類型和可選的命名空間
    • selector           ;可選的選擇器表達式字元串,用於移除代理事件
    • fn                    ;待移除的監聽函數,可以設置為false,表示內部定義的只返回false的函數
  • off(types,selector,fn)   ;移除匹配元素中每個元素上綁定的一個或多個類型的監聽函數
    • types        ;一個或多個以空格分隔的事件類型和可選的命名空間
    • selector    ;可選的選擇器表達式字元串,用於移除代理事件
    • fn          ;待移除的監聽函數,可以設置為false
  • bind(types,data,fn)            ;綁定一個普通事件
  • trigger(type, data)                  執行每個匹配元素上綁定的監聽函數和預設行為,並模擬冒泡過程
  • one(types,selector,data,fn)    ;為匹配元素集合中的每個元素綁定最多執行一次的事件監聽函數
  • hover(fnOver, fnOut)              ;用於在匹配元素上綁定一個或兩個監聽函數,當滑鼠指針進入和離開時,綁定的監聽函數被執行

我們還是以上一節的實例為例,用實例方法改寫一下,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    <style>div{width: 200px;padding-top:50px;height: 150px;background: #ced;}div button{margin:0 auto;display: block;}</style>
</head>
<body>
    <div>        
        <button id="button">按鈕1</button>    
    </div>
    <script>
        $("div").on('click',()=>console.log('div普通單擊事件'));
        $('div').on('click','button',()=>console.log('d1代理事件'))
    </script>
</body>
</html>

渲染如下:

和上一節一樣,我們在div上綁定了一個普通事件和代理事件,當點擊div時觸發普通事件,點擊按鈕時分別觸發普通事件和代理事件。

另外為了更方變使用事件,jQuery還定義了很多的便捷事件方法,可以直接在jQuery實例上調用,註意:便捷方法不能綁定代理事件,只能綁定普通事件,所有的便捷方法如下:

blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu

我們將上面的例子改寫一下,用便捷方法來實現,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    <style>div{width: 200px;padding-top:50px;height: 150px;background: #ced;}div button{margin:0 auto;display: block;}</style>
</head>
<body>
    <div>        
        <button id="button">按鈕1</button>    
    </div>
    <script>
        $("div").click(()=>console.log('div普通單擊事件'));                //用便捷事件來實現
        $('div').on('click','button',()=>console.log('d1代理事件'))        //代理事件不能用便捷方法來操作,因此我們用實例方法來實現
    </script>
</body>
</html>

效果和上面是一樣的。

 

源碼分析


實例方法是定義在jQuery.fn上的,on主要對參數做一些判斷,以支持多種格式的調用方法,實現如下:

jQuery.fn.extend({

    on: function( types, selector, data, fn, /*INTERNAL*/ one ) {    //該方法主要是修正參數。為匹配元素集合中的每個元素綁定一個或多個類型的事件監聽函數。
        var origFn, type;

        // Types can be a map of types/handlers                            //如果types是對象時,即參數格式是.on(Object,selector,data,one)或.one(Object,data,one)則
        if ( typeof types === "object" ) {
            // ( types-Object, selector, data )
            if ( typeof selector !== "string" ) {
                // ( types-Object, data )
                data = selector;
                selector = undefined;
            }
            for ( type in types ) {                                            //遍歷參數types,遞歸調用方法.on(types,selector,data,fn,one)綁定事件。
                this.on( type, selector, data, types[ type ], one );
            }
            return this;
        }

        if ( data == null && fn == null ) {                                //如果沒有參數3、4,則認為格式是.on(types,fn)
            // ( types, fn )
            fn = selector;                                                    //把第二個參數修正為fn。
            data = selector = undefined;
        } else if ( fn == null ) {                                        //傳入了三個參數時
            if ( typeof selector === "string" ) {                            //如果第二個參數是字元串,則認為格式是:.on(types,selector,fn)    忽略參數data,並把第三個參數作為參數fn。
                // ( types, selector, fn )
                fn = data;
                data = undefined;
            } else {                                                        //否則則認為忽略參數selector,並把第而個參數作為參數data,並把第三個參數作為參數fn。格式是.on(types,data,fn)
                // ( types, data, fn )
                fn = data;
                data = selector;
                selector = undefined;
            }
        }
        if ( fn === false ) {                                            //如果參數fn是布爾值false,則把它修正為總返回false的函數returnFalse()。
            fn = returnFalse;
        } else if ( !fn ) {                                                //如果fn沒有值則直接返回。
            return this;
        }

        if ( one === 1 ) {                                                //當方法one()調用.on()時,該參數為1,就會把監聽函數fn重新封裝為一個只會執行一次的新監聽函數。
            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 this.each( function() {                                    //遍歷當前的this
            jQuery.event.add( this, types, fn, data, selector );            //調用add()綁定事件
        });    
    },    
    one: function( types, selector, data, fn ) {                        //為匹配元素集合中的每個元素綁定一個或多個類型的事件監聽函數,每個監聽函數在每個匹配元素上最多執行一次。該方法簡單的通過調用.on(types,selector,data,fn,one)來實現。
        return this.on.call( this, types, selector, data, fn, 1 );
    },
    /**/
})

對於便捷方法來說,他就是在$.fn上定義每一個屬性,值為一個函數,內部還是調用$.fn.on來實現添加事件的,如下:

jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
    "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
    "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {    //參數1是一個數組 參數2是個函數,其中name是值,比如blur、focus

    // Handle event binding
    jQuery.fn[ name ] = function( data, fn ) {            //初始化事件便捷方法,在jQuery.fn對象上添加元素,這樣jQuery實例就可以直接訪問了
        if ( fn == null ) {                                    //修正參數,如果只傳入一個參數,則把該參數視為fn參數,把data視為null
            fn = data;
            data = null;
        }

        return arguments.length > 0 ?                        //根據參數個數決定是綁定事件還是觸發事件
            this.on( name, null, data, fn ) :                     //如果參數個數大於1,則調用方法.on()綁定事件監聽函數
            this.trigger( name );                                 //如果沒有參數,則調用方法.trigger()觸發事件監聽函數和預設行為
    };

    if ( jQuery.attrFn ) {                                    //記錄事件便捷方法名,在調用jQuery.attr()讀取或設置HTML屬性時,如果屬性名與事件便捷方法名同名,則會改為調用同名的事件便捷方法a
        jQuery.attrFn[ name ] = true;
    }

    if ( rkeyEvent.test( name ) ) {
        jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
    }

    if ( rmouseEvent.test( name ) ) {
        jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
    }
});

可以看到,如果執行便捷方法時不傳遞參數將觸發該事件,例如:$('div').click()將會觸發在該div上綁定的普通事件。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 對象(object)是 JavaScript 最重要的數據結構。ES6 對它進行了重大升級,本章介紹數據結構本身的改變及語法應用細節。 ...
  • “JSX” JSX就是Javascript和XML結合的一種格式。是一個 JavaScript 的語法擴展。 React發明瞭JSX,利用HTML語法來創建虛擬DOM。當遇到<,JSX就當HTML解析,遇到{就當JavaScript解析。 JSX,是一個 JavaScript 的語法擴展。JSX 可 ...
  • vue,element列表大數據卡頓問題,vue列表渲染慢,element表格渲染慢,表格渲染慢(卡),表格全選卡 ...
  • 結論 3XX開頭的HTTP狀態碼都表示重定向的響應。 301、308是永久重定向;302、303、307是臨時重定向。 301、302是http 1.0的內容,303、307、308是http1.1的內容。 301和302本來在規範中是不允許重定向時改變請求method的(將POST改為GET),實 ...
  • 1. Safari 3D變換會忽略z index的層級 在Safari瀏覽器下(此Safari瀏覽器包括iOS的Safari,iPhone上的微信瀏覽器,以及Mac OS X系統的Safari瀏覽器),當我們使用3D transform變換的時候,如果祖先元素沒有overflow:hidden/sc ...
  • Link: "原文鏈接" 譯文開始: 對網站進行性能優化對一個最容易的方法就是把JS和CSS進行打包壓縮。但是當你需要調試這些壓縮文件中的代碼的時候,會發生什麼?可能會是一場噩夢。但是,不用害怕,即將有一個解決方案到來,它就是Source Maps。 source maps提供一種將壓縮文件中的代碼 ...
  • 元素拖拽 作者:一粒塵土 時間:2019 10 30 使用範圍:兩個元素位置交換,移動元素到指定位置 涉及函數 |屬性|解釋 |: |: | |draggable|是否允許元素進行拖拽| |dragstart|拖拽開始觸發的函數,可在此獲取元素| |dragover|在目標元素內進行拖動時觸發的函數 ...
  • 從今天開始,持續更新typescript入門教程系列.... 目前ts越來越火,主流的前端框架,好比 angular,vue 3 均是採用ts來編寫,所有很多公司的項目都是用 ts 來寫的,所有是時候認真學習 ts 了 ts來源於微軟公司,越是大的公司,越是大的項目,越是推薦使用ts來編碼,ts是j ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...