jQuery 源码分析(十七) 事件系统模块 实例方法和便捷方法 详解
程序员文章站
2022-06-24 12:51:17
实例方法和便捷方法是指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上绑定的普通事件。