zoukankan      html  css  js  c++  java
  • jquery源码之事件系统-- jQuery.event

    每个网站,交互的核心都是事件。浏览器环境一般提供两种事件绑定的方式:

    一个是通过dom句柄的使用。如: element.onclick = function() {}

    另一种就是事件委托了,如:docuement.addEventListener(element, function() {});

    基于第二种,不同浏览器也有不用的api接口。这是需要注意的地方

    当然,如果使用jquery,这些东西都不是你要关心的,他会替你解决一切。

    jquery事件系统的强大是毋庸置疑的。那我们就来看看他到底强大在哪。

    首先jquery事件系统是基于$.data缓存系统的,这个在先前的博文就有提及到。

    jquery事件系统功能是非常强大的,所以它的块头也比较大。所以我们不能一口就把它给全吃掉。

    我们以一定得顺序来探索jquery时间系统。我们首先看看jquery核心方法jquery.event.add,再由jquery.fn.on这个统一入口逐层分析整个事件系统。

    让我们先来看看 jquery的核心绑定事件的方法。

    jquery.event.add = function( elem, types, handler, data, selector ) {
    
    		var 
    			// 该dom元素的缓存数据
    			elemData, 
    			// 事件处理函数
    			eventHandle, 
    			// 该元素对应的事件集合
    			events,
    			t, tns, type, 
    			// 命名空间
    			namespaces, 
    			// 处理对象
    			handleObj,
    			handleObjIn, handlers, special;
    		
    		// 在不支持添加事件的元素上就直接返回
    		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
    		// 在这一步中 通过jquery._data 获取了该元素对应的数据
    		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
    		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
    		if ( !handler.guid ) {
    			handler.guid = jQuery.guid++;
    		}
    		// 取出缓存对象中对应event事件的对象集合
    		// Init the element's event structure and main handler, if this is the first
    		events = elemData.events;
    		// 不存在则新建一个{}
    		if ( !events ) {
    			elemData.events = events = {};
    		}
    		// 事件处理函数
    		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
    				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
    			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++ ) {
    
    			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 = jQuery.event.special[ type ] || {};
    
    			// 获取准确的事件类型
    			// If selector defined, determine special event api type, otherwise given type
    			type = ( selector ? special.delegateType : special.bindType ) || type;
    
    			// 更新special
    			// 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,
    				needsContext: selector && jQuery.expr.match.needsContext.test( 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;
    	}
    

      

  • 相关阅读:
    小兔生仔和汽水换瓶的两个算法
    dpi 编程
    作者赠送的《我的第一本c++书》收到啦
    什么是程序员的优良品质
    如何把事情做对?
    学习应有的态度
    魔方数算法
    我的第二本c++教科书
    如何处理人际关系
    电动玩具的开发思路
  • 原文地址:https://www.cnblogs.com/w2154/p/4591797.html
Copyright © 2011-2022 走看看