事件的委托是什么?事件代理?
- 前面总结了事件监听(addEventListener)的使用方法,其实用它直接绑定新的元素可能会报dom不存在的错误。先不说它是为什么会出现这种情况;
- 重点是我们要解决:未来不清楚会创建多少个节点,没办法实现给它们注册事件的这个难题,就要用到事件委托(代理)这一理念。
1)事件委托的原理
事件委托就是利用冒泡的原理,把事件加到父元素甚至祖先元素上,触发执行效果。也就是通过一个事件程序去管理一个类型的所有事件。
先来套用一个广为流传的小故事:希望不厌其烦。
取快递 | |
---|---|
现在的年轻人呀,每天的快递总是连绵不断的。比如说勤劳的上班族们:小红、小张、小王三人分别有一些快递,预计将在周三早上签收。
A方式:
周三早上他们都站在公司门口等待着快递,(不考虑滑稽性)。
B方式:
他们让前台小美代收快递。
现实中我们都会选择第二种方式,前台会确认收件人是谁,并根据三人的要求签收;如果还有其他的人(不管人数多少)也想让前台帮忙签收,前台也是愿意的,会按同样的方式完成。
映射到事件的委托:
- (1)满足前台可以签收快递的情况。即程序中现有的DOM节点存在事件。
- (2)三人以外的其他人也可以让前台代为签收。即程序中新添加的DOM节点也存在事件。
2)事件委托怎么用?
一个父元素(祖先元素)有很多子元素,直接设置事件处理程序可能会带给节点多次的交互和访问,性能降低。这时用事件委托来触发事件再好不过,交互一次,实现操作。
(1) 固定节点的事件委托
eg: 点击li元素节点时,它的样式颜色变为“red”
<ul>
<li id="a">1</li>
<li id="b">2</li>
<p>这是委托测试</p>
</ul>
var ul=document.getElementsByTagName("ul")[0];
ul.onclick=function(e){
var target=e.target||e.srcElement;
if(target.nodeName.toLowerCase()==="li")
{
target.style.color="red";
}
}
- 代码解析:
- target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。
- IE下,event对象有srcElement属性,但是没有target属性; Firefox下,event对象有target属性,但是没有srcElement属性。两者作用是相当的。
结果:(分别点击li元素节点)
对比:
- 事件委托只执行一次DOM操作就完成所有效果,对比一般节点操作(需要遍历子节点Li,去执行触发了点击事件的子节点li),明显的性能更好。
(2) 动态增加节点的事件委托
给原来的页面动态增加元素节点ul,数量不限制。代码如下:
- 页面新增标签:
<button class="btn">增加</button>
- js执行代码:
var ul=document.getElementsByTagName("ul")[0];
var btn=document.getElementsByClassName("btn")[0];
var p=document.getElementsByTagName("p")[0];
var num=2;
ul.onclick=function(e) {
var target = e.target || e.srcElement; //IE下,event对象有srcElement属性; Firefox下,event对象有target属性
if (target.nodeName.toLowerCase() === "li")//完全等同
{
target.style.color = "red";
}
}
btn.onclick=function(){
num++;
var ab=document.createElement("li");
ab.innerHTML=1*num;
ul.appendChild(ab);
//向节点添加最后一个子节点
ul.insertBefore(ab,p);
//将li添加在子节点p之前
}
结果如图:(随机点击li子节点,触发点击事件的li变红)
对比:
- 一般节点执行方法需要写一个触发事件执行的函数,当新创建的节点触发该事件时,调用此函数执行。
- 事件委托方法只执行一次DOM操作就完成。
3)事件委托的发光点
- 事件委托不需要遍历,给父级元素添加事件,有操作执行就好。事件委托方法只执行一次DOM操作就完成。
- 性能优化。