jQuery之事件绑定到触发全过程及知识点补充

栏目: jQuery · 发布时间: 5年前

内容简介:前言:最重要的还是最后的流程图,可以试着根据流程图手写实现

jQuery之事件绑定到触发全过程及知识点补充

前言:

最重要的还是最后的流程图,可以试着根据流程图手写实现 $().on() ,下篇文章会放出模拟实现的代码。

一、举例

<div id="A" style="background-color: deeppink">
  这是A

    <div id="C" style="background-color: aqua">
    这是C
    </div>

</div>

  $("#A").on("click" ,function (event) {
    console.log(event,"A被点击了")
  })

  $("#A").on("click" ,"#C",function (event) {
    console.log(event,"点击了C,即C委托A的click事件被点击了")
  })

二、 $().on()

(1)进行参数的调整

(2)调用 jQuery.event.add() 方法

三、 jQuery.event.add() 最终调用 elem.addEventListener() 来绑定事件

注意:

(1)绑定常用的事件(如:click、focus),使用 handleObj 保存

handleObj = jQuery.extend( {
          //click,mouseout...
          type: type,
          //click,mouseout...
          origType: origType,
          data: data,
          //事件处理函数,如 function(){console.log('aaaa')}
          handler: handler,
          //索引,用于关联元素和事件
          guid: handler.guid,
          //事件委托的标志,也是委托的对象选择器
          selector: selector,
          needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
          //命名空间,同一click事件有两个事件处理程序handler的话,
          //用这个标识,方便删除或添加handler
          namespace: namespaces.join( "." )
        }, handleObjIn );

(2)如果绑定的是自定义事件(如:windowResize),则使用handleObjIn保存

if ( handler.handler ) {
   handleObjIn = handler;
   handler = handleObjIn.handler;
   selector = handleObjIn.selector;
}

(1)、(2)都会初始化事件处理器(addEventListener):

//第一次绑定事件,走这里
        // Init the event handler queue if we're the first
        if ( !( handlers = events[ type ] ) ) {
          handlers = events[ type ] = [];
          handlers.delegateCount = 0;
          // Only use addEventListener if the special events handler returns false
          if ( !special.setup ||
            special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
            //目标元素有addEventListener的话,调用绑定click事件
            //eventHandle就绑定到addEventListener上
            if ( elem.addEventListener ) {
              elem.addEventListener( type, eventHandle );
            }
          }
        }

四、jQuery的事件绑定为何不直接绑定在目标元素身上,而是元素和事件分离?

打印 $("#A")

console.log($("#A"),'aaaaaa46')

jQuery之事件绑定到触发全过程及知识点补充

不要在意jQueryId不同的问题,每次刷新网页它都会变化

jQuery之事件绑定到触发全过程及知识点补充

可以看到

jQuery的事件和触发事件的handler是分离的,

事件集合 存在 事件缓存 dataPrivevents 上,

//获取数据缓存
elemData = dataPriv.get( elem );

而handler是由 jQuery.event.dispatch() 处理

elemData.handle = function( e ) {
  jQuery.event.dispatch.apply( elem, arguments )
}

为什么要分离?因为元素如果绑定click事件一百次,很耗内存。所以需要将这一百个同类型的事件保存到一个click事件集合中,然后在这一大个click事件集合内,根据guid来执行某一次的click处理代码

同一事件的处理:

$('body').on('click', '#one', function(e) {
  show('委托到one触发')
})
$('body').on('click', '#two', function(e) {
  show('委托到two触发')
})

events是jQuery内部的事件队列

handle是真正绑定到element上的事件处理函数

body:{
  events:{
    click:[
      0:{
        guid: 1,
        data: undefined,
        namespace: "",
        origType: "click",
        //事件委托的标志
        selector: "#one",
        type: "click",
        handler: function(){xxx},
        }
      1:{
        guid: 2,
        data: undefined,
        namespace: "",
        origType: "click",
        //事件委托的标志
        selector: "#two",
        type: "click",
        handler: function(){xxx},
        }
    ]
  },
  handle: function(){
    jQuery.event.dispatch.apply( elem, arguments )
  }
}

可以看到,针对同一类型的事件(如click),重复绑定不会再创建新的内存(new Object会有新内存),而是在events里添加新的绑定事件。

记得看第十一点!

五、 guid 的作用?

添加 guid 的目的是因为 handler 没有直接跟元素节点发生关联,所以需要一个索引来寻找或者删除 handler

六、命名空间 namespace 的作用?

$("#one").on("click.one",function () {
   console.log("one被点击了")
 })
 $("#one").on("click.two",function () {
   console.log("two被点击了")
 })

命名空间为:

#one:{
  events:{
    click:[
      0:{
        namespace: "one",
        handler: function(){console.log("one被点击了")},
        }
      1:{
        namespace: "two",
        handler: function(){xxx},
        }
    ]
  },
}

利用命名空间删除事件:

$("#one").off("click.one")

七、jQuery.event.special 的处理机制

绑定的事件,有些是不能统一处理的,比如 load 事件,是不支持冒泡的,所以即使开发者未用 event.stopPropagation ,jQuery也要阻止其冒泡:

jQuery.event ={
  special: {
    load: {
        // Prevent triggered image.load events from bubbling to window.load
        //阻止冒泡
        noBubble: true
    },
    focus: {
        // Fire native event if possible so blur/focus sequence is correct
        trigger: function() { },
        delegateType: "focusin"
    },
  }
}

八、外部是Event,内部是数据缓存events,两者是不一样的

外部Event:

$().on("click","#B",function(event){
  console.log("A被点击了")
})

//click的event就是jQuery.Event
jQuery.Event{
  handleObj{
    data:undefined,
    guid: 2,
    handler:function(){console.log("A被点击了")},
    namespace: "clickA",
    origType: "click",
    selector: "#B",
    type: "click.clickA",
  },
  originalEvent:{
    //就是MouseEvent
  },
  target:div#B,
  type: "click",
  delegateTarget: div#A,
  //fix 的标志
  jQuery331087940272164138: true,
  currentTarget: div#A,
  isDefaultPrevented:xxx,
  timeStamp:Date.now(),
  isDefaultPrevented:function(){return false}
}

内部缓存events:

let events = dataPriv.get( this, "events" )

events[
    delegantCount:1,
   {
      data:undefined,
      guid: 2,
      handler:function(){console.log("B委托A被点击了")},
      namespace: "clickA",
      origType: "click",
      selector: "#B",
      type: "click.clickA",
    },
   {
     data:undefined,
      guid: 1,
      handler:function(){console.log("A被点击了")},
      namespace: "",
      origType: "click",
      selector: undefined,
      type: "click",
    }   


]

九、为什么要使用 fix() 来重构 js 的原生 MouseEvent 对象呢?

(1)jQuery 有自己的一套 event 处理机制,所以需要符合 jQueryevent 对象

(2)可以传递 data 数据,即用户自定义的数据。

十、trigger的触发机制

$("#A").on("click" ,function (event) {
    console.log(event,"A被点击了")
  })

元素 #A 本身绑定了一个 click 事件,但是 click 是原生事件,它是靠 addEventListener 绑定来触发事件的。

但是! jQuerytrigger 是能够无差别模拟这个交互行为的

$("#A").trigger("click")

trigger() 的功能上就可以解释 为什么 jQuery 要设计元素与数据分离 了:

如果是直接绑定的话就无法通过 trigger 的机制去触发 click 事件,

正是因为 jQuery 没有直接把事件相关的 handler 与元素直接绑定,而是采用了分离处理,

所以我们通过 trigger 触发 click 事件与 addEventListener 触发 click 事件的处理流程是 一致 的,不同的只是触发的方式而已。

但是,通 trigger 触发的事件是没有事件对象(event)、冒泡(bubble)这些特性的,所以我们需要有一个功能 能模拟出事件对象,然后生成一个遍历树(eventPath)模拟出冒泡行为,这个就交给了 trigger 方法了

关于 $().trigger() 的源码解析请看: jQuery源码解析之trigger()

最后,附上自己做的 jQuery 事件绑定到触发全过程的流程图:

jQuery之事件绑定到触发全过程及知识点补充

jQuery之事件绑定到触发全过程及知识点补充

(完)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mastering Bitcoin

Mastering Bitcoin

Andreas M. Antonopoulos / O'Reilly Media / 2014-12-20 / USD 34.99

Mastering Bitcoin tells you everything you need to know about joining one of the most exciting revolutions since the invention of the web: digital money. Bitcoin is the first successful digital curren......一起来看看 《Mastering Bitcoin》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具