内容简介:前言:最重要的还是最后的流程图,可以试着根据流程图手写实现
前言:
最重要的还是最后的流程图,可以试着根据流程图手写实现 $().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')
不要在意jQueryId不同的问题,每次刷新网页它都会变化
可以看到
jQuery的事件和触发事件的handler是分离的,
事件集合 存在 事件缓存 dataPriv
的 events
上,
//获取数据缓存 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
处理机制,所以需要符合 jQuery
的 event
对象
(2)可以传递 data 数据,即用户自定义的数据。
十、trigger的触发机制
$("#A").on("click" ,function (event) { console.log(event,"A被点击了") })
元素 #A
本身绑定了一个 click
事件,但是 click
是原生事件,它是靠 addEventListener
绑定来触发事件的。
但是! jQuery
的 trigger
是能够无差别模拟这个交互行为的
$("#A").trigger("click")
从 trigger()
的功能上就可以解释 为什么 jQuery
要设计元素与数据分离 了:
如果是直接绑定的话就无法通过 trigger
的机制去触发 click
事件,
正是因为 jQuery
没有直接把事件相关的 handler
与元素直接绑定,而是采用了分离处理,
所以我们通过 trigger
触发 click
事件与 addEventListener
触发 click
事件的处理流程是 一致 的,不同的只是触发的方式而已。
但是,通 trigger
触发的事件是没有事件对象(event)、冒泡(bubble)这些特性的,所以我们需要有一个功能 能模拟出事件对象,然后生成一个遍历树(eventPath)模拟出冒泡行为,这个就交给了 trigger
方法了
关于 $().trigger()
的源码解析请看: jQuery源码解析之trigger()
最后,附上自己做的 jQuery
事件绑定到触发全过程的流程图:
(完)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design systems
Not all design systems are equally effective. Some can generate coherent user experiences, others produce confusing patchwork designs. Some inspire teams to contribute to them, others are neglected. S......一起来看看 《Design systems》 这本书的介绍吧!