jQuery的event系統實現思路比較特殊,把event和handle緩衝在cache裡,為元素繫結統一的事件處理函數,觸發時從cache中找對應的處理函數執行。
最核心的是add方法,看懂這個方法就明白event是如何?的了。
// Bind an event to an element<br />// Original by Dean Edwards<br />add: function( elem, types, handler, data ) {<br />// elem文本節點和注釋直接返回,不註冊事件<br />if ( elem.nodeType === 3 || elem.nodeType === 8 ) {<br />return;<br />}<br />// For whatever reason, IE has trouble passing the window object<br />// around, causing it to be cloned in the process<br />if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {<br />elem = window;<br />}<br />// Make sure that the function being executed has a unique ID<br />// 給每個處理函數分配一個uuid<br />if ( !handler.guid ) {<br />handler.guid = jQuery.guid++;<br />}<br />// if data is passed, bind to handler<br />// 資料繫結在handler上<br />if ( data !== undefined ) {<br />// Create temporary function pointer to original handler<br />var fn = handler;<br />// Create unique handler function, wrapped around original handler<br />handler = jQuery.proxy( fn );<br />// Store data in unique handler<br />handler.data = data;<br />}<br />// Init the element's event structure<br />// 初始化元素event資料結構,event<br />var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),<br />handle = jQuery.data( elem, "handle" ), eventHandle;</p><p>if ( !handle ) {// 建立handle並添加到elem的data裡,一個元素只建立一次handle<br />eventHandle = function() {<br />// Handle the second event of a trigger and when<br />// an event is called after a page has unloaded<br />return typeof jQuery !== "undefined" && !jQuery.event.triggered ?<br />jQuery.event.handle.apply( eventHandle.elem, arguments ) :<br />undefined;<br />};<br />handle = jQuery.data( elem, "handle", eventHandle );<br />}<br />// If no handle is found then we must be trying to bind to one of the<br />// banned noData elements<br />// 如果沒有handle返回,不添加事件處理<br />if ( !handle ) {<br />return;<br />}<br />// Add elem as a property of the handle function<br />// This is to prevent a memory leak with non-native<br />// event in IE.<br />// 把elem作為handle方法的一個屬性,阻止IE下非原生事件造成記憶體泄露<br />handle.elem = elem;<br />// Handle multiple events separated by a space<br />// jQuery(...).bind("mouseover mouseout", fn);<br />// 處理綁定多個事件的情況<br />types = types.split( //s+/ );<br />var type, i=0;<br />while ( (type = types[ i++ ]) ) {<br />// Namespaced event handlers<br />var namespaces = type.split(".");<br />type = namespaces.shift();<br />handler.type = namespaces.slice(0).sort().join(".");<br />// Get the current list of functions bound to this event<br />var handlers = events[ type ],<br />special = this.special[ type ] || {};//特殊事件 ready live remove beforeunload mouseenter mouseleave focusin focusout等<br />// Init the event handler queue<br />// 如果沒有type的event隊列則建立<br />if ( !handlers ) {<br />handlers = events[ type ] = {};<br />// Check for a special event handler<br />// Only use addEventListener/attachEvent if the special<br />// events handler returns false<br />if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {<br />// Bind the global event handler to the element<br />if ( elem.addEventListener ) {<br />elem.addEventListener( type, handle, false );<br />} else if ( elem.attachEvent ) {<br />elem.attachEvent( "on" + type, handle );<br />}<br />}<br />}<br />//處理特殊事件<br />if ( special.add ) {<br />var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );<br />if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {<br />modifiedHandler.guid = modifiedHandler.guid || handler.guid;<br />handler = modifiedHandler;<br />}<br />} </p><p>// Add the function to the element's handler list<br />handlers[ handler.guid ] = handler;<br />// Keep track of which events have been used, for global triggering<br />this.global[ type ] = true;<br />}<br />// Nullify elem to prevent memory leaks in IE<br />elem = null;<br />},<br /> // 統一的事件處理函數<br />handle: function( event ) {<br />// returned undefined or false<br />var all, handlers;<br />event = arguments[0] = jQuery.event.fix( event || window.event );<br />event.currentTarget = this;<br />// Namespaced event handlers<br />var namespaces = event.type.split(".");<br />event.type = namespaces.shift();<br />// Cache this now, all = true means, any handler<br />all = !namespaces.length && !event.exclusive;<br />var namespace = new RegExp("(^|//.)" + namespaces.slice(0).sort().join("//.(?:.*//.)?") + "(//.|$)");<br />handlers = ( jQuery.data(this, "events") || {} )[ event.type ];<br />for ( var j in handlers ) {<br />var handler = handlers[ j ];<br />// Filter the functions by class<br />if ( all || namespace.test(handler.type) ) {<br />// Pass in a reference to the handler function itself<br />// So that we can later remove it<br />event.handler = handler;<br />event.data = handler.data;<br />var ret = handler.apply( this, arguments );<br />if ( ret !== undefined ) {<br />event.result = ret;<br />if ( ret === false ) {//處理函數返回false,取消事件的預設動作,不再派發事件<br />event.preventDefault();<br />event.stopPropagation();<br />}<br />}<br />if ( event.isImmediatePropagationStopped() ) {<br />break;<br />}<br />}<br />}<br />return event.result;<br />},