zoukankan      html  css  js  c++  java
  • 【jQuery源码】事件存储结构

    a. jQuery事件原型——Dean Edwards的跨浏览器AddEvent()设计


      源码解读

     View Code
    重新梳理一下数据结构,使用一个例子
    复制代码
    <input type="text" id="chua" onClick="f0();">
    
    function f0(){...}
    function f1(){...}
    function f2(){...}
    function f3(){...}
    var dom = document.getElementById("chua");
    
    addEvent(dom,"click",f1);
    addEvent(dom,"change",f1);
    addEvent(dom,"change",f2);
    addEvent(dom,"click",f3);
    addEvent(dom,"change",f3);
    复制代码

      经过addEvent()函数之后,当前的数据结构为:

    复制代码
    element: {
      onclick: handleEvent(event),   //click事件的主监听函数
      onchage: handleEvent(event),  //change事件的主监听函数
      events: {     click:{//这是一个类数组       0: f0, //element已有的事件       1: f1,  //下标1实际上就是f1.$$guid       3: f3 //下标3实际上就是f3.$$guid,需要注意的是每一个响应事件都有一个唯一的$$guid作为下标       ...     },     change:{//这是一个类数组       1: f1,
          2: f2,
          3: f3     } } }
    复制代码

      事件系统会根据调用addEvent的顺序给每个响应函数(也就是addEvent(element, type, handler)中的第三个参数handler)打上标记$$guid。源码

      //保证每个不同的事件响应函数只有唯一一个id
        if (!handler.$$guid) handler.$$guid = addEvent.guid++;

      最终三个响应函数的$$guid标记分别是

      f1.$$guid = 1

      f2.$$guid = 2

      f3.$$guid = 3

      而根据源码中

        handlers[handler.$$guid] = handler;

      那么某一个函数在任何事件响应函数集合中的下标位置是固定的。比如click和change事件都调用f3作为响应事件,那么f3在element.events.click以及element.events.change中的下标位置都是f3.$$guid = 3;即element.events.click[3] = element.events.change[3] = f3。

      这个时候假设又新添了一个事件绑定:addEvent(dom,"focus",f3);那么element.events.focus[3] = f3;这也是对象相比于数组的方便之处,数组不可能没有下标0,1,2就直接有3了,但是对象却可以,此时3是作为对象的一个属性名称。

      这样的设计,其实已经具备了jquery事件系统的雏形,包含了几个最主要的特点:

      1)element上的所有事件,将保存到element.events属性中,不是直接绑定到element上;这样一个事件可以有无数个响应函数。

      2)handleEvent作为element所有事件的“主监听函数”,有它统一管理element上的所有函数。

      3)所有浏览器都支持element["on" + type]事件绑定方式,跨浏览器兼容。

      

      好啦,明白了addEvent的事件结构,这个想法确实让人觉得眼前一亮。下面分析jQuery的事件结构

    b. jQuery的事件结构


      所有的函数添加事件都会进入jQuery.event.add函数。该函数有两个主要功能:添加事件、附加很多事件相关信息。我们直接上源码,源码思想和Dean Edwards的跨浏览器兼容事件添加处理类似。

      源码分析

     View Code

      依然用实例来说明jQuery的事件结构

    复制代码
    <div id="#center"></div>
    
    <script>
      function dohander(){console.log("dohander")};
      function dot(){console.log("dot");}
    
      $(document).on("click",'#center',dohander)
      .on("click",'#center',dot)
      .on("click",dot);
    </script>
    复制代码

      经过添加处理环节,事件添加到了元素上,而且节点对应的缓存数据也添加了相应的数据。结构如下

    复制代码
    elemData = jQuery._data( elem );
    elemData = {
      events: {
        click: {//Array[3]
          0: {
            data: undefined/{...},
            guid: 2, //处理函数的id
            handler: function dohander(){…},
            namespace: "",
            needsContext: false,
            origType: "click",
            selector: "#center",//选择器,用来区分不同事件源
            type: "click"
          }
          1: {
            data: undefined/{...},
            guid: 3,
            handler: function dot(){…},
            namespace: "",
            needsContext: false,
            origType: "click",
            selector: "#center",
            type: "click"
          }
          2: {
            data: undefined,
            guid: 3,
            handler: function dot(){…},
            namespace: "",
            needsContext: false,
            origType: "click",
            selector: undefined,
            type: "click"
          }
          delegateCount: 2,//委托事件数量,有selector的才是委托事件
          length: 3
        }
      }
      handle: function ( e ) {…}/*事件处理主入口*/{
        elem: document//属于handle对象的特征
      }
    }
    复制代码

      jQuery的处理和Dean Edwards的跨浏览器兼容事件添加处理类似,比如为每一个函数添加guid;使用events对象存放响应事件列表,有一个总的事件处理入口handle等。

      jQuery做了哪些改进?

      1)事件数据不再直接保存在节点上,而是使用jQuery缓存系统内(内部使用的缓存jQuery._data方式存取)

      2)事件委托:绑定到当前节点(例子中当前节点是document根节点)的处理函数不仅仅包含当前节点触发事件(click)响应时处理的事件(例子中selector为undefined时对应的处理函数dot);还代理了其他节点(例子中的#center节点)触发事件(click)响应时处理的事件(例子中selector为"#center"对应的处理事件doHandler和dot);委托机制在后续分析。

      3)增加了很多功能数据,比如命名空间namespace:这个主要用在自定义事件自定义触发,比如$(document).on("chua.click",'#center',dot),主动触发$("#center").trigger("chua.click")。还有额外数据data:虽然没有看到那个地方有被用到。

  • 相关阅读:
    京东架构师:前端工程化在京东首页实践
    CSS 的命名和书写
    call,apply,bind方法的总结
    this指针指向的彻底理解
    Js获取当前日期时间及其它操作
    gulp-css-spriter 雪碧图合成
    Web前端业界氛围极好的群——鬼懿IT
    默认加载数据分页,点击分页后再次异步数据
    height设置百分比的条件
    input 的type类型值
  • 原文地址:https://www.cnblogs.com/shytong/p/5376311.html
Copyright © 2011-2022 走看看