内容简介:前言:最重要的还是最后的流程图,可以试着根据流程图手写实现
前言:
最重要的还是最后的流程图,可以试着根据流程图手写实现 $().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 事件绑定到触发全过程的流程图:
(完)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
破茧成蝶:用户体验设计师的成长之路
刘津、李月 / 人民邮电出版社 / 2014-7 / 69.00
市面上已经有很多专业的用户体验书籍,但解决用户体验设计师在职场中遇到的众多现实问题的图书并不多见。本书从用户体验设计师的角度出发,系统地介绍了其职业生涯中的学习方法、思维方式、工作流程等,覆盖了用户体验设计基础知识、设计师的角色和职业困惑、工作流程、需求分析、设计规划和设计标准、项目跟进和成果检验、设计师职业修养以及需要具备的意识等,力图帮助设计师解决在项目中遇到的一些常见问题,找到自己的职业成长......一起来看看 《破茧成蝶:用户体验设计师的成长之路》 这本书的介绍吧!