jQuery的event系统实现思路比较特殊,把event和handle缓存在cache里,为元素绑定统一的事件处理函数,触发时从cache中找对应的处理函数执行。 最核心的是add方法,看懂这个方法就明白event是如何实现的了。 // Bind an event to an element // Original by Dean Edwards add: function( elem, types, handler, data ) { // elem文本节点和注释直接返回,不注册事件 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // For whatever reason, IE has trouble passing the window object // around, causing it to be cloned in the process if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { elem = window; } // Make sure that the function being executed has a unique ID // 给每个处理函数分配一个uuid if ( !handler.guid ) { handler.guid = jQuery.guid++; } // if data is passed, bind to handler // 数据绑定在handler上 if ( data !== undefined ) { // Create temporary function pointer to original handler var fn = handler; // Create unique handler function, wrapped around original handler handler = jQuery.proxy( fn ); // Store data in unique handler handler.data = data; } // Init the element's event structure // 初始化元素event数据结构,event var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ), handle = jQuery.data( elem, "handle" ), eventHandle; if ( !handle ) {// 创建handle并添加到elem的data里,一个元素只创建一次handle eventHandle = function() { // Handle the second event of a trigger and when // an event is called after a page has unloaded return typeof jQuery !== "undefined" && !jQuery.event.triggered ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; handle = jQuery.data( elem, "handle", eventHandle ); } // If no handle is found then we must be trying to bind to one of the // banned noData elements // 如果没有handle返回,不添加事件处理 if ( !handle ) { return; } // Add elem as a property of the handle function // This is to prevent a memory leak with non-native // event in IE. // 把elem作为handle方法的一个属性,阻止IE下非原生事件造成内存泄露 handle.elem = elem; // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); // 处理绑定多个事件的情况 types = types.split( //s+/ ); var type, i=0; while ( (type = types[ i++ ]) ) { // Namespaced event handlers var namespaces = type.split("."); type = namespaces.shift(); handler.type = namespaces.slice(0).sort().join("."); // Get the current list of functions bound to this event var handlers = events[ type ], special = this.special[ type ] || {};//特殊事件 ready live remove beforeunload mouseenter mouseleave focusin focusout等 // Init the event handler queue // 如果没有type的event队列则创建 if ( !handlers ) { handlers = events[ type ] = {}; // Check for a special event handler // Only use addEventListener/attachEvent if the special // events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, handle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, handle ); } } } //处理特殊事件 if ( special.add ) { var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { modifiedHandler.guid = modifiedHandler.guid || handler.guid; handler = modifiedHandler; } } // Add the function to the element's handler list handlers[ handler.guid ] = handler; // Keep track of which events have been used, for global triggering this.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, // 统一的事件处理函数 handle: function( event ) { // returned undefined or false var all, handlers; event = arguments[0] = jQuery.event.fix( event || window.event ); event.currentTarget = this; // Namespaced event handlers var namespaces = event.type.split("."); event.type = namespaces.shift(); // Cache this now, all = true means, any handler all = !namespaces.length && !event.exclusive; var namespace = new RegExp("(^|//.)" + namespaces.slice(0).sort().join("//.(?:.*//.)?") + "(//.|$)"); handlers = ( jQuery.data(this, "events") || {} )[ event.type ]; for ( var j in handlers ) { var handler = handlers[ j ]; // Filter the functions by class if ( all || namespace.test(handler.type) ) { // Pass in a reference to the handler function itself // So that we can later remove it event.handler = handler; event.data = handler.data; var ret = handler.apply( this, arguments ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) {//处理函数返回false,取消事件的默认动作,不再派发事件 event.preventDefault(); event.stopPropagation(); } } if ( event.isImmediatePropagationStopped() ) { break; } } } return event.result; },