jQuery源码学习(版本1.11)-事件处理-工具函数jQuery.event

概述

本文详细分析jquery-1.11.1.js源码文件行数:4269~4906;
代码简介:定义了jQuery.event命名空间,存放了事件处理底层的工具函数add-增加事件监听,remove-移除事件监听,trigger-触发事件,dispatch-事件分发等,JQ对象利用JQ原型方法添加事件时,最终都会调用到jQuer.event里的工具方法。
下文进行详细代码分析。

jQuery.event

// 事件管理的工具函数
jQuery.event = {

	global: {},

	// 添加绑定事件
	add: function( elem, types, handler, data, selector ) {
		var tmp, events, t, handleObjIn,
			special, eventHandle, handleObj,
			handlers, type, namespaces, origType,
			// 获取elem在jQuery.cache中对应的缓存(如果没定义_data会自动初始化一个新的)
			elemData = jQuery._data( elem );

		// elemData即缓存不存在,说明elem不适合绑定事件,直接返回
		if ( !elemData ) {
			return;
		}

		// 处理handler是一个object而不单纯是funciton的场景
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// 为handler增加一个独有id,用于remove判断解除绑定的是不是同一个回调(我估计是直接用===比较引用会损耗性能)
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// 初始化缓存里的events对象,后面用于保存事件类型和对应回调
		if ( !(events = elemData.events) ) {
			events = elemData.events = {};
		}
		// 初始化elemData.handle,统一执行所有回调的函数
		if ( !(eventHandle = elemData.handle) ) {
			eventHandle = elemData.handle = function( e ) {
				// 分发处理事件,trigger方法中会使用原生监听方法将eventHandle作为原生方法的回调
				return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
					undefined;
			};
			// 防止IE内存泄露
			eventHandle.elem = elem;
		}

		// 本方法支持事件类型用空格隔开传入,处理type保存了多种事件类型的场景,将其分割开
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			// rtypenamespace这个正则是用来匹配"."前后片段的,最终过滤得到type是需要的事件类型
			// 具体考虑场景暂时还不确定,估计是用来兼容一些传入了命名空间的场景
			// 命名空间是提供一种根据不同命名空间来处理事件的机制
			tmp = rtypenamespace.exec( types[t] ) || [];
			// 由代码可推测tmp[1]是原始类型
			type = origType = tmp[1];
			// tmp[2]是命名空间,使用split分割成数组
			namespaces = ( tmp[2] || "" ).split( "." ).sort();

			//最终得到需要的type,不存在的话就循环下一个
			if ( !type ) {
				continue;
			}

			// 获取其special里保存的事件类型对应的对象
			// 后面代码可知,load,focus,blur,click,beforeunload五种事件类型均有对应的特殊对象
			// 不存在则使用空对象
			special = jQuery.event.special[ type ] || {};

			// 如果selector存在,则使用special.delegateType作为type,否则使用special.bindType 
			// special.delegateType和special.bindType都为空(前面special可能只是空对象),则不改变type
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// 上一行代码type可能改变了,因此更新一下对应的special对象
			special = jQuery.event.special[ type ] || {};

			// 构造一个handleObj
			// 这里使用extend方法将handleObjIn扩展进handleObj,假如handleObjIn为空,就会直接返回handleObj
			// extend内部确定需要扩展的target时,使用的是形参长度,因此只要用来扩展的对象传了形参,即使为空,也不会变为将handleObj扩展进jQuery
			// 只当传了一个参数时,target才会变为this,即jQuery本身
			handleObj = jQuery.extend({
				type: type,
				origType: origType,
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
				// 保存命名空间,网上查找用法说是可让用户根据命名空间,对事件进行不同的处理
				namespace: namespaces.join(".")
			}, handleObjIn );

			// 初始化该事件类型的缓存
			if ( !(handlers = events[ type ]) ) {
				// 初始化缓存数组handlers,用于保存回调
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// setup暂时不理解是什么东西
				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
					// 调用elem.addEventListener或elem.attachEvent监听事件,回调使用eventHandle
					// eventHandle里面调用jQuery.event.dispatch,会对缓存里面的对应事件类型回调一一执行
					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle, false );

					} else if ( elem.attachEvent ) {
						elem.attachEvent( "on" + type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				// 感觉这是多余的分支,从前面代码分析,handleObj.handler跟handler永远是相同的引用
				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// 将回调handleObj添加进handlers
			if ( selector ) {
				// 这里使用splice时插入对象(handlers.delegateCount是位置,第二个参数是0表明不删除,第三个是需要插入数组的对象,会被放在handlers.delegateCount前面)
				// 由于是插入的,因此事件分发执行的时候也会被优先执行
				handlers.splice( handlers.delega
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值