• jQuery 源码分析(十七) 事件系统模块 实例方法和便捷方法 详解


    实例方法和便捷方法是指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上绑定的普通事件。

  • 相关阅读:
    脱离Table组件的render苦海
    激活码
    Unittest
    IO多路复用-EPOOL 详细
    PIL-Image、ImageDraw图像标记
    Mysql专场
    xshell命令
    并发编程
    Mysql高级用法
    视图函数中进行sql查询,防止sql注入
  • 原文地址:https://www.cnblogs.com/greatdesert/p/11679507.html
Copyright © 2020-2023  润新知