从onClick谈事件代理和了解事件传播机制
在javasript
中delegate
这个词经常出现,看字面的意思,代理、委托。
要搞懂事件代理,我们先来看看什么是代理,相信我们生活中现在还有朋友在做微商的,而微商的产品就是一级一级代理,下家找上家拿货这样子,你卖了东西从上家拿货,这个过程相当于你也有了货
我们怎么从字面上来了解事件的代理呢?慢慢来,我们先来看一个需求,有这样一个列表,当我们每次点击的时候,就在控制台打印列表里的内容
作为一名新手,我经常这样绑定onclick
事件
我会循环每一个li
当我点击一个在控制台显示打印结果,全部绑定click
事件,于是,我的代码是这样的
<ul class="ct">
<li>我是一号</li>
<li>我是二号</li>
<li>我是三号</li>
<li>我是四号</li>
<li>我是五号</li>
</ul>
<button type = "button" id="btn">增加</button>
var ul = document.querySelector(".ct")
for(var i=0;i<ul.children.length;i++){
ul.children[i].onclick = function(){
console.log(this.innerText)
}
}
代码没有问题
我觉得这样写的挺好的,可是有人说这样会耗费性能,那我就不管了,可是当我改了一下需求,我发现这个代码用的没那么舒服了
我在代码中通过js加入新的li,当我点击新的li时,控制台没有打印我的代码?怎么回事?
我加入了几这样的代码
var btn =document.querySelector("#btn")
var i =6
btn.addEventListener("click",function(){
var node = document.createElement("li")
node.innerText = "我是" + i++ + "号"
ul.appendChild(node)
})
后面增加的li没有在控制台打印
这是为什么?因为原有的li跟我后面生成的li根本不是同时发生的,在创建新的li元素之前,已经给存在的li加事件了,好吧,那我怎么修改呢?难道要重新循环遍历,太麻烦了,
有人告诉我可以用代理,代理是什么,看了文章,好吧,修改一下代码
ul.addEventListener("click",function(e){
// 检查事件源e.targe是否为Li
if(e.target.nodeName.toLowerCase() == 'li'){
console.log(e.target.innerText)
}
})
成功了
新增新的点击
li
也会再控制台打印,解决了,于是耐心翻资料看了一下什么是事件代理:
定义:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
那什么是冒泡呢?
- 当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡
回到我们本文的这个例子,看看改动后的代码,我把onlick事件绑定到了ul标签上面,而不是li标签。
于是,当我点击任何一个li标签
(不管是动态生成的还是之前就有的)是,这个事件就开始冒泡,寻找父元素。由于我这里给ul绑定了onlick,那么这时,ul会捕获冒泡上来的onclick事件。
接着,如果,这个target刚刚好就是li标if(target.nodeName.toLowerCase() == 'li')
,那么执行函数。
简单介绍一下事件传播机制,主要介绍DOM2.0
- DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。如图:
-
事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
-
事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
-
事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。