jQuery事件處理(一)


1、jQuery事件綁定的用法:

$( "elem" ).on( events, [selector], [data], handler );

events:事件名稱,可以是自定義事件名稱

selector:選擇器

data:事件觸發時傳遞給事件處理函數

handler:事件處理函數

2、on方法源碼分析

on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
  var origFn, type;

  // 如果types是對象,則說明是傳入了多個事件
  if ( typeof types === "object" ) {
    // 如果selector不是string,則說明用戶沒有傳入selector
    if ( typeof selector !== "string" ) {
      // 把selector賦值給data
      data = data || selector;

      // selector置為undefined
      selector = undefined;
    }

    // 遍歷types對象中的每一個元素,並遞歸調用自身
    for ( type in types ) {
      this.on( type, selector, data, types[ type ], one );
    }
    return this;
  }

  // 如果data和fn都為null,說明用戶只傳了前兩個參數

  if ( data == null && fn == null ) {
    // 把selector(第二個參數)賦值給fn
    fn = selector;

    // data和selector置為undefined
    data = selector = undefined;

  // 如果fn為null,說明用戶傳了三個參數
  } else if ( fn == null ) {

    // 如果selector的類型是string,說明用戶沒傳data
    if ( typeof selector === "string" ) {
      // 把data賦值給fn
      fn = data;

      // 把data置為undefined
      data = undefined;
    } else {
      // 否則的話,說明用戶沒傳selector,而是傳了data,將data賦值給fn

      fn = data;

      // 將selector賦值給data
      data = selector;

      // 將selector置為undefined
      selector = undefined;
    }
  }

  // 如果用戶傳入的事件處理函數是false值,則將事件處理函數賦值為jQuery內部的returnFalse函數
  if ( fn === false ) {
    fn = returnFalse;

  // 如果用戶沒傳回調函數,返回this,this是啥?返回this干嘛?
  } else if ( !fn ) {
    return this;
  }

  // 如果one為1,內部用,暫時沒看到用途

  if ( one === 1 ) {
    origFn = fn;
    fn = function( event ) {
      // Can use an empty set, since event contains the info
      jQuery().off( event );
      return origFn.apply( this, arguments );
    };
    // Use same guid so caller can remove using origFn
    fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  }

  // 遍歷this對象,調用jQueryevent對象的add方法處理事件
  return this.each( function() {
    jQuery.event.add( this, types, fn, data, selector );
  });
},

通過分析on方法的源碼發現,on方法並沒有處理事件相關的任何事情,只是對用戶傳入的參數進行調整,真正處理事件的是event對象

3、首先看看event對象的構造函數都做了什么

jQuery.Event = function( src, props ) {
  // 余老板的suggest組件中也用到了這種方法

  // 檢測this是不是Event對象,如果不是,new一個Event對象出來,這樣就避免了外部new對象
  if ( !(this instanceof jQuery.Event) ) {
    return new jQuery.Event( src, props );
  }

  // 如果有src,並且src有type屬性
  if ( src && src.type ) {

    // 定義originalEvent屬性並將src賦值給它
    this.originalEvent = src;

    // 定義type屬性,並將src.type賦值給它
    this.type = src.type;

    // 定義isDefaultPrevented屬性並通過判斷事件被阻止冒泡為其賦值
    this.isDefaultPrevented = ( src.defaultPrevented ||
      src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;

  // 否則,將src賦值給type
  } else {
    this.type = src;
  }

  // 如果用戶傳入props,則擴展Event或者覆蓋原有的屬性
  if ( props ) {
    jQuery.extend( this, props );
  }

  // 創建一個時間戳??
  this.timeStamp = src && src.timeStamp || jQuery.now();

  // 給這個Event對象一個標記
  this[ jQuery.expando ] = true;
};

看event對象的構造函數發現,構造函數做了一些初始化操作。在看一下event對象封裝的一些方法。

4、jQuery的event對象

  jQuery的event對象提供了如下方法和屬性:

    {

      add : function(){},

      remove : function(){},

      trigger : function(){},

      dispatch : function(){},

      handlers : function(){},

      fix: function(){},

      simulate : function(){},

      global : {},

      props : {},

      fixHooks : {},

      keyHooks : {},

      mouseHooks : {},

      special : {}

    }

  首先看add方法:

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

    var handleObjIn, eventHandle, tmp,
      events, t, handleObj,
      special, handlers, type, namespaces, origType,
      elemData = data_priv.get( elem );

    // 涉及到jQuery的另外一個大的方面:緩存機制。或許我應該先看緩存機制的。。。

    // 不為text、comment節點綁定數據,直接返回
    if ( !elemData ) {
      return;
    }

    // 如果handler是一個有handler屬性或方法的對象,則進行一些轉移賦值操作
    if ( handler.handler ) {
      handleObjIn = handler;
      handler = handleObjIn.handler;
      selector = handleObjIn.selector;
    }

    // 檢查handler是否有一個唯一的id,方便之后查找和刪除
    if ( !handler.guid ) {

      // 如果沒有就為其設定一個唯一id
      handler.guid = jQuery.guid++;
    }

    // 如果elemData中沒有events對象,則為其定義events屬性並賦值為空對象
    if ( !(events = elemData.events) ) {
      events = elemData.events = {};
    }

    // 如果elemData中沒有handle對象
    if ( !(eventHandle = elemData.handle) ) {

      // 為elemData定義一個handle方法(事件處理函數)
      eventHandle = elemData.handle = function( e ) {
        // 有點迷糊。。。
        return typeof jQuery !== core_strundefined && (!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;
    }

    // 處理types中傳入的是通過空格分割的多個事件的情況
    types = ( types || "" ).match( core_rnotwhite ) || [""];
      t = types.length;
      while ( t-- ) {
        tmp = rtypenamespace.exec( types[t] ) || [];
        type = origType = tmp[1];
        namespaces = ( tmp[2] || "" ).split( "." ).sort();

        if ( !type ) {
          continue;
      }

      // 事件是否會改變當前狀態,如果是則使用特殊事件,看event的special屬性。。。
      special = jQuery.event.special[ type ] || {};

      // 根據是否有selector判斷使用哪種特殊事件(看完特殊事件再過來看這個地方)
      type = ( selector ? special.delegateType : special.bindType ) || type;

      // 根據新的type獲取新的special
      special = jQuery.event.special[ type ] || {};

      // 組裝用於特殊事件處理的對象
      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 = events[ type ] = [];
        handlers.delegateCount = 0;

        // 如果獲取特殊事件監聽方法失敗,則使用addEventListener添加事件(拋棄attachEvent了嗎?)
        if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
          if ( elem.addEventListener ) {
            elem.addEventListener( type, eventHandle, false );
          }
        }
      }

      // 使用special的add方法進行處理

      if ( special.add ) {

        // 添加事件
        special.add.call( elem, handleObj );

        // 設置handleObj中的handler屬性的id

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

      // ???
      if ( selector ) {
        handlers.splice( handlers.delegateCount++, 0, handleObj );
      } else {
        handlers.push( handleObj );
      }

      // 現在還沒看到是干啥用的。
      jQuery.event.global[ type ] = true;
    }

    // 將elem清空,等待回收,避免內存泄漏
    elem = null;
  },


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM