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;
  },

jQuery事件处理(一)的更多相关文章

  1. [DOM Event Learning] Section 3 jQuery事件处理基础 on(), off()和one()方法使用

    [DOM Event Learning] Section 3 jQuery事件处理基础 on(),off()和one()方法使用   jQuery提供了简单的方法来向选择器(对应页面上的元素)绑定事件 ...

  2. jQuery事件处理了解一下

    >>> JQuery 事件处理 一.事件绑定方式 1.事件绑定的快捷方式: 缺点:绑定的事件,无法取消 $("button:eq(0)").dblclick(fu ...

  3. jQuery事件处理(四)

    看了几天,决定整理一下jQuery事件处理的整体设计思路 1.通过add方法给选中的元素注册事件处理程序(通过缓存系统将事件储存到cache,而不是绑定到元素上) a.在存储之前,会为事件处理程序增加 ...

  4. Unit02: jQuery事件处理 、 jQuery动画

    Unit02: jQuery事件处理 . jQuery动画 jQuery实现购物车案例 <!DOCTYPE html> <html> <head> <titl ...

  5. JQuery事件处理的注意事项

    1.jQuery 名称冲突 jQuery 使用 $ 符号作为 jQuery 的简介方式. 某些其他 JavaScript 库中的函数(比如 Prototype)同样使用 $ 符号. jQuery 使用 ...

  6. 02-老马jQuery教程-jQuery事件处理

    1. 绑定简单事件 在DOM中DOM0级绑定事件的方式是直接给事件属性赋值,但是这样有个缺点就是每次指定的事件处理程序会把之前的覆盖掉. jQuery简单绑定事件的方式,可以让我绑定多个事件处理程序跟 ...

  7. jQuery事件处理(七)

    1.自定义事件(用户手动trigger的一般都是自定义事件) trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tm ...

  8. jQuery事件处理(六)

    1.通过一步步调试的的方法观察了一下存放到cache中的事件及其处理程序的数据格式: { events : { // 根据事件类型存放添加到该元素上的所有事件,下面以click为例 click : [ ...

  9. jQuery事件处理(五)

    对原生js不熟悉看jQuery会困难很多.后续需要更多的关注下原生js jQuery封装之后的事件触发,其中一个分支(处理普通事件)是通过:elem.addEventListener( type, e ...

随机推荐

  1. at 命令

    每天什么时候执形at 12:00 /every:Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday shutdown -r

  2. php 字符串 以 开头 以结尾 startWith endWith

    From: http://www.shipingzhong.cn/node/1217 //第一个是原串,第二个是 部份串function startWith($str, $needle) { retu ...

  3. Logback中文文档(三):配置

    在第一部分,我们将介绍配置 logback 的各种方法,给出了很多配置脚本例子.在第二部分,我们将介绍 Joran,它是一个通用配置框架,你可以在自己的项目里使用 Joran. Logback里的配置 ...

  4. UNIX环境编程学习笔记(26)——多线程编程(一):创建和终止线程

    lienhua342014-11-08 在进程控制三部曲中我们学习了进程的创建.终止以及获取终止状态等的进程控制原语.线程的控制与进程的控制有相似之处,在表 1中我们列出了进程和线程相对应的控制原语. ...

  5. 性能监控-TP理解

    首先给出Google到的答案: The tp90 is a minimum time under which 90% of requests have been served. tp90 = top ...

  6. Linux定时运行程序脚本

    项目开发中经常需要用将某个脚本定时运行从而避免其运行并不会影响到其他程序.虽说可以在脚本中利用sleep命令来做这一点,Linux自带了crontab命令可以很好的执行这一操作. 比如我们有名为som ...

  7. Android输出日志到电脑磁盘

    使用Eclipse查看Log有时候挺恶心的,有些Log ADB会自动的清除,所有有时候导致抓不到有效的Log,把Log保存到文件,然后通过文本查看器查看,感觉好Happy,下面就是脚本文件: adb ...

  8. Eclipse------maven使用Maven build编译web项目显示" javax.servlet.http 不存在"

    缺少javax.servlet包 解决方法: 引入下面代码即可 <project> <dependencies> <dependency> <groupId& ...

  9. SQLServer------备份与还原

    转载: http://www.cnblogs.com/zgqys1980/archive/2012/07/04/2576382.html

  10. 第四章 TCP粘包/拆包问题的解决之道---4.1---

    4.1 TCP粘包/拆包 TCP是一个“流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可 ...