jQuery Event add [ 源码分析 ]

/*
 * Helper functions for managing events -- not part of the public interface.
 * Props to Dean Edwards' addEvent library for many of the ideas.
 */
jQuery.event = {

	add: function( elem, types, handler, data, selector ) {

		var elemData, eventHandle, events,
			t, tns, type, namespaces, handleObj,
			handleObjIn, quick, handlers, special;

		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
		if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
			return;
		}

		// Caller can pass in an object of custom data in lieu of the handler
		// 这里在之前一直不明白为什么要这么做,原因就是这里的handler 可以是一个function,即我们平时所说的绑定的事件方法
		// 同时也可以是一个事件对象,也就是下面所说的handleObj,那么如果是在jQuery的内部是可以传递一个事件对象过来的
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// Make sure that the handler has a unique ID, used to find/remove it later
		// 这里分配guid
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure and main handler, if this is the first
		// 从缓存系统中,从缓存事件对象中获取events数组
		events = elemData.events;
		if ( !events ) {
			elemData.events = events = {};
		}
		//主监听函数,唯一一个绑定到dom元素的方法,会调用dispatch分配事件
		eventHandle = elemData.handle;
		if ( !eventHandle ) {
			elemData.handle = eventHandle = function( e ) {
				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				//这里主要防止trigger 手动触发时的二次冒泡。这里在trigger中,会存在模拟冒泡的事件,
				//主要针对不能冒泡的事件如:focus 就只能模拟冒泡事件
				//如果已经冒泡过了,那么在这里就不需要再次执行了。
				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
					undefined;
			};
			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
			// 这里主要针对ie的内存问题
			eventHandle.elem = elem;
		}

		// Handle multiple events separated by a space
		// jQuery(...).bind("mouseover mouseout", fn);
		// 切割多个事件组合
		types = jQuery.trim( hoverHack(types) ).split( " " );
		for ( t = 0; t < types.length; t++ ) {
			//使用正则切割命名空间
			//	rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
			//	如: click.namespace ,hover.namespace
			//	==> ["click.namespace", "click", "namespace", index: 0, input: "click.namespace"]
			tns = rtypenamespace.exec( types[t] ) || [];
			type = tns[1];
			namespaces = ( tns[2] || "" ).split( "." ).sort();

			// If event changes its type, use the special event handlers for the changed type
			// 这里主要对事件进行修复,看是否在special中存有定义,如果有,刚使用special中的事件类型替换之
			// 主要是某些原生事件,对浏览器存在兼容问题,所以需要替换
			special = jQuery.event.special[ type ] || {};

			// If selector defined, determine special event api type, otherwise given type
			// 这里的selector为代理事件,如果存在selector,那么就存在冒泡事件
			// 对于delegateType主要是对原生不能冒泡的事件进行替换如:focus => focusin
			// 那么如果原生事件对于冒泡没有问题,那么检测绑定类型是否需要修复:如: mouseover ==> mouseenter
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// Update special based on newly reset type
			special = jQuery.event.special[ type ] || {};

			// handleObj is passed to all event handlers
			handleObj = jQuery.extend({
				type: type,
				origType: tns[1],
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				quick: selector && quickParse( selector ),
				namespace: namespaces.join(".")
			}, handleObjIn );

			// Init the event handler queue if we're the first
			handlers = events[ type ];
			if ( !handlers ) {
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// Only use addEventListener/attachEvent if the special events handler returns false
				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
					// Bind the global event handler to the element
					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 );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add to the element's handler list, delegates in front
			if ( selector ) {
				handlers.splice( handlers.delegateCount++, 0, handleObj );
			} else {
				handlers.push( handleObj );
			}

			// Keep track of which events have ever been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	}

时间: 2024-10-05 23:06:13

jQuery Event add [ 源码分析 ]的相关文章

Jquery之isPlainObject源码分析

今天对Jquery中 isPlainObject 源码分析. 1.  isPlainObject 方法的作用: 用来判断传入参数,是否是对象. 2. 源码分析:isPlainObject: function( obj ) { // 1. jQuery.type( obj ): 通过 juery 封装的类型判断方法,如果不是 Object类型,返回false // 2. obj.nodeType : 用来判断是否是dom 节点, 如果是,返回 false // 3. jQuery.isWindow

jquery ui widget 源码分析

jquery ui 的所有组件都是基于一个简单,可重用的widget. 这个widget是jquery ui的核心部分,实用它能实现一致的API,创建有状态的插件,而无需关心插件的内部转换. $.widget( name, base, prototype ) widget一共有2或3个参数.base为可选. 这里之所以把base放在第二个参数里,主要是因为这样写代码更直观一些.(因为后面的prototype 是个代码非常长的大对象). name:第一个参数是一个包含一个命名空间和组件名称的字符串

jQuery实现jsonp源码分析(京东2015面试)

// Bind script tag hack transportjQuery.ajaxTransport( "script", function(s) { // This transport only deals with cross domain requests if ( s.crossDomain ) { var script, head = document.head || jQuery("head")[0] || document.documentEle

jQuery Sizzle 入口 [ 源码分析 ]

var Sizzle = function( selector, context, results, seed ) { //context 默认为document,可以人为指定 results = results || []; context = context || document; var origContext = context; //判断文档节点 if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return [

jQuery Sizzle.find [ 源码分析 ]

Sizzle.find = function( expr, context, isXML ) { var set, i, len, match, type, left; //expr是否为空 if ( !expr ) { return []; } for ( i = 0, len = Expr.order.length; i < len; i++ ) { type = Expr.order[i]; //根据Expr.order,即Sizzle.selectors.order 的四种类型:ID,C

jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on

转:http://www.cnblogs.com/aaronjs/p/3440647.html?winzoom=1 事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析实现的, 所以需要有一定的基础才行 为了下一步更好的理解内部的实现,所以首先得清楚的认识到事件接口的划分 网上资料遍地都是,但是作为一个jQuery系列的源码分析,我还是很有必要在重新

jQuery1.9.1源码分析--数据缓存Data模块

阅读目录 jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(elem, name, data)源码分析 internalRemoveData方法源码分析 internalData方法的源码分析 jQuery.fn.extend({data: function( key, value ) {}})源码分析 jQuery.extend({removeData: function( elem, name ) {}})源码分

Android 源码分析(十一) 事件传递机制

一.介绍 Android三种事件类型:ACTION_DOWN,ACTOIN_MOVE,ACTION_UP. 事件传递的三个阶段: 分发(Dispatch) 方法:public boolean dispatchTouchEvent(MotionEvent ev) 拦截(Intercept) 方法:public boolean onInterceptTouchEvent(MotionEvent ev) 消费(Consume) 方法:public boolean onTouchEvent(Motion

集合之LinkedList(含JDK1.8源码分析)

LinkedList的数据结构 LinkedList的增删改查 增:add 说明:add函数用于向LinkedList中添加一个元素,并且添加到链表尾部.具体添加到尾部的逻辑是由linkLast函数完成的. 举例: public class Test { public static void main(String[] args) { List<String> list = new LinkedList<>(); list.add("zhangsan"); li