内容简介:前言:请
前言:
请 先 回顾下我之前写的一篇文章: JavaScript之事件委托
一、事件委托(委派)
含义:
在 #A 上绑定 click 事件,但是让 #B 触发 click 事件, 相当于在 #B 上假绑定了 click 事件
也就是说:#B 委托了 click 事件给了 #A(在 #A 上绑定)
举例:
<div id="A" style="background-color: deeppink">
这是A
<div id="B" style="background-color: bisque">
这是B
<div id="C" style="background-color: aqua">
这是C
</div>
<div id="D" style="background-color: blueviolet">
这是D
</div>
</div>
</div>
//在父元素上绑定click事件,但只能由子元素触发父元素上绑定的事件
$("#A").on("click" ,"#B",function (e) {
console.log("点击了B,即B委托A的click事件被点击了")
})
$("#A").on("click" ,"#C",function (e) {
console.log(e,"点击了C,即C委托A的click事件被点击了")
})
二、jQuery 的事件委托顺序:
举例:
(1)A、B、C 各自绑定了 click 事件
$("#A").on("click" ,function () {
console.log("A被点击了")
})
$("#B").on("click" ,function () {
console.log("B被点击了")
})
$("#C").on("click",function () {
console.log("C被点击了")
})
点击 C,会依次执行 C、B、A 的 click 事件
输出结果:
① C 被点击了
② B 被点击了
③ A 被点击了
(2)A 自己绑定了 click 事件,同时 B、C 还委托给 A 绑定 click 事件
$("#A").on("click" ,function () {
console.log("A被点击了")
})
$("#A").on("click" ,"#B",function () {
console.log("点击了B,即B委托A的click事件被点击了")
})
$("#A").on("click" ,"#C",function () {
console.log("点击了C,即C委托A的click事件被点击了")
})
点击 C,依次执行 C、B 委托给 A 的 click 事件,最后执行 A 自己的 click 事件
输出结果:
① 点击了 C,即 C 委托 A 的 click 事件被点击了
② 点击了 B,即 B 委托 A 的 click 事件被点击了
③ A 被点击了
(3)A 自己绑定了 click 事件,同时 B、C 还委托给 A 绑定 click 事件,同时 B、C 还有自己的 click 事件:
$("#A").on("click" ,function () {
console.log("A被点击了")
})
$("#A").on("click" ,"#B",function () {
console.log("点击了B,即B委托A的click事件被点击了")
})
$("#A").on("click" ,"#C",function () {
console.log("点击了C,即C委托A的click事件被点击了")
})
$("#B").on("click" ,function () {
console.log("B被点击了")
})
$("#C").on("click",function () {
console.log("C被点击了")
})
点击 C,依次执行:C 自己的事件、B 自己的事件、C 委托给 A 的 click 事件、B委托给 A 的 click 事件、A 自己的 click 事件。
输出结果:
① C 被点击了
② B 被点击了
③ 点击了 C,即 C 委托 A 的 click 事件被点击了
④ 点击了 B,即 B 委托 A 的 click 事件被点击了
⑤ A 被点击了
综上,jQuery事件委托的顺序为:
(1) 先统一 处理自身、父元素 自身 绑定的事件
(2) 再统一 处理自身、父元素 委托 给祖先元素的绑定事件
(3) 最后 祖先元素处理 自身 的事件
简练说,就是:
先处理子元素委托给自身的事件,再处理自身的事件。
源码:
$().on() —> jQuery.event.add()
jQuery.event = {
//源码5241行
//this, types, fn, data, selector
//#A,'click',function(){console.log('A被点击了')},undefined,undefined
//#A,'click',function(){点击了C,即C委托A的click事件被点击了},undefined,#C
add: function( elem, types, handler, data, selector ) {
xxx
...
//优先添加委托handler,再添加其他handler
// Add to the element's handler list, delegates in front
//delegateCount即委托在#A上的事件数量
if ( selector ) {
//在下标为handlers.delegateCount++的位置插入委托事件
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
}
解析:
可以看到,jQuery 是优先添加委托 click 事件,再添加自身 click 事件,触发事件的时候也是按这个顺序。
注意:
如下的例子,点击 E 是不能触发 click 事件的,因为冒泡冒不到 A 上:
<div id="A" style="background-color: deeppink">
这是A
</div>
<div id="E" style="background-color: brown">这是E</div>
$("#A").on("click" ,"#E",function (event) {
console.log(event,"点击了E,即E委托A的click事件被点击了")
})
三、jQuery 绑定事件上的 event 上的 target、currenttarget 和 delegateTarget 的区别?
target 是触发事件的对象
delegateTarget 是事件委托的 原对象
而currenttarget分三种情况:
(1)A 在自身有绑定 click 事件的条件下,C 再去委托 A 绑定 click 事件
<div id="A" style="background-color: deeppink">
这是A
<div id="B" style="background-color: bisque">
这是B
<div id="C" style="background-color: aqua">
这是C
</div>
<div id="D" style="background-color: blueviolet">
这是D
</div>
</div>
</div>
$("#A").on("click" ,function (event) {
console.log(event,"A被点击了")
})
$("#A").on("click" ,"#C",function (event) {
console.log(event,"点击了C,即C委托A的click事件被点击了")
})
$("#C").on("click",function (event) {
console.log(event,"C被点击了")
})
① 点击了C,即 C 委托 A 的 click 事件被点击了
event 的结构如下:
可以看到,
target 是 #C,currenttarget 是 #A,delegateTarget 是 #A
也就是说:
target 是触发 click 事件的对象 #C,currenttarget 是 #C 委托绑定click事件的 #A,并且 #A 自身有绑定 click 事件
② A被点击了
target 是 #A,currenttarget 是 #A,delegateTarget 是 #A
③ C被点击了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C
(2)A 自身没有绑定 click 事件,C 委托 A 绑定 click 事件
<div id="A" style="background-color: deeppink">
这是A
<div id="B" style="background-color: bisque">
这是B
<div id="C" style="background-color: aqua">
这是C
</div>
<div id="D" style="background-color: blueviolet">
这是D
</div>
</div>
</div>
$("#A").on("click" ,"#C",function (event) {
console.log(event,"点击了C,即C委托A的click事件被点击了")
})
$("#C").on("click",function (event) {
console.log(event,"C被点击了")
})
① 点击了 C,即 C 委托 A 的 click 事件被点击了
event 的结构如下:
可以看到,
target 是 #C, currenttarget 是 #C,而不是 #A ,delegateTarget 是 #A
也就是说:
target 是触发 click 事件的对象 #C,currenttarget 是 #C,因为 #C 委托 #A 绑定 click 事件,并且 #A 自身没有绑定 click 事件
② C被点击了
target是 #C,currenttarget 是 #C,delegateTarget 是 #C
(3)A在自身有绑定click事件的条件下,C再去委托A绑定click事件的同时,阻止冒泡!
<div id="A" style="background-color: deeppink">
这是A
<div id="B" style="background-color: bisque">
这是B
<div id="C" style="background-color: aqua">
这是C
</div>
<div id="D" style="background-color: blueviolet">
这是D
</div>
</div>
</div>
$("#A").on("click" ,"#C",function (event) {
event.stopPropagation()
console.log(event,"点击了C,即C委托A的click事件被点击了")
})
$("#C").on("click",function (event) {
console.log(event,"C被点击了")
})
① 点击了C,即C委托A的click事件被点击了
event 的结构如下:
可以看到,
target 是 #C, currenttarget 是 #C,而不是 #A ,delegateTarget 是 #A
② C 被点击了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C
为什么是这样?
我们来分析下jQuery源码:
$().on() —>
jQuery.event.add() —>
elem.addEventListener( type, eventHandle ) ,
eventHandle —>
jQuery.event.dispatch
currenttarget在 jQuery.event.dispatch 中定义,所以我们看 jQuery.event.dispatch 部分源码:
jQuery.event = {
//源码5472行
//nativeEvent即原生MouseEvent
dispatch: function( nativeEvent ) {
//获取handler队列
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
//如果没有阻止冒泡的话,那么
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
event.currentTarget = matched.elem;
}
}
//源码5547行
//组装事件处理队列
//event是fix过的MouseEvent, handlers
handlers: function( event, handlers ) {
//目标元素
var cur = event.target;
for ( ; cur !== this; cur = cur.parentNode || this ) {
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
matchedHandlers = [];
matchedSelectors = {};
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
//sel就是#C
// Don't conflict with Object.prototype properties (#13203)
sel = handleObj.selector + " ";
if ( matchedSelectors[ sel ] === undefined ) {
matchedSelectors[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) > -1 :
//注意:jQuery.find()和jQuery().find()是不一样的
jQuery.find( sel, this, null, [ cur ] ).length;
}
if ( matchedSelectors[ sel ] ) {
matchedHandlers.push( handleObj );
}
}
}
if ( matchedHandlers.length ) {
handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
}
}
// Add the remaining (directly-bound) handlers
//#A
cur = this;
//1<2 true
//1<1 false
//将除委托事件的事件(如自身绑定的事件)放入handlerQueue中
if ( delegateCount < handlers.length ) {
handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
}
}
}
解析:
event.currentTarget —> handlerQueue[ i++ ] —> jQuery.event.handlers
jQuery.event.handlers:
for循环的意思是:
(1)只要cur不等于this,即#A,就一直循环
每次循环:
(2)将matchedHandlers 置为
[ ]
(3)循环委托绑定的事件数量
循环委托绑定:
(4) matchedHandlers 根据 handleObj.selector 是否有值,push handleObj
按照我们的例子来看,当 cur=event.target,cur=#C,然后进入冒泡循环,再进入委托事件循环,
关键是:jQuery.find(),
cur=#C 的时候,matchedSelectors[ sel ]=jQuery.find( sel, this, null, [ cur ] ).length=1
但是 cur=#B 的时候(冒泡循环), matchedSelectors[ sel ]=0 ,也就是说 jQuery.find() 不同于 $().find ,它是冒泡找 cur 元素!
所以 matchedHandlers 只 push length!==0 的委托事件,所以 cur 就是 #C 了(新循环中的当前值)。
然后
cur = this;
cur 又等于 this,即 #A,最后将除委托事件的事件(如自身绑定的事件)放入 handlerQueue 中,cur=#A
再拿例子举,即(2)A 自身没有绑定 click 事件,C 委托 A 绑定 click 事件
只有一个 handler,并且是委托 handler,
handlerQueue[
{
elem:#C,
...
},
]
//#C
event.currentTarget = handlerQueue[0].elem
(1)A 在自身有绑定 click 事件的条件下,C 再去委托 A 绑定 click 事件
有两个 handler
handlerQueue[
{
elem:#C,
...
},
{
elem:#A,
...
},
]
//#C
event.currentTarget = handlerQueue[0].elem
//#A
event.currentTarget = handlerQueue[1].elem
因为 #A 只有一个 event ,所以在循环 handlerQueue[i] 时, event.currenttarget 最终被 #A 所覆盖
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
//最终被#A所覆盖
event.currentTarget = matched.elem;
}
(3)A在自身有绑定click事件的条件下,C再去委托A绑定click事件的同时,阻止冒泡!
因为 !event.isPropagationStopped() ,所以 event.currentTarget=#C ,未被 #A 覆盖。
(完)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- js事件委托总结
- JQuery7:事件委托
- Kotlin Vocabulary:Kotlin 委托代理
- 通过发布订阅模式实现的事件委托
- BeetleX之XRPC远程委托调用
- 委托、匿名方法到lambda表达式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ANSI Common Lisp
Paul Graham / Prentice Hall / 1995-11-12 / USD 116.40
For use as a core text supplement in any course covering common LISP such as Artificial Intelligence or Concepts of Programming Languages. Teaching students new and more powerful ways of thinking abo......一起来看看 《ANSI Common Lisp》 这本书的介绍吧!