今天呢,咱们来说说事件委托,有的相关资料叫事件代理.
首先呢,先来讲讲事件委托的起源:由于事件处理程序可以为web应用提供交互能力,因此很多开发人员会不分青红皂白的向页面中添加大量的处理程序.在js中,添加到页面的事件处理程序数量直接关系到页面的整体运维性能.导致这一问题的原因是多方面的.首先:
1 函数都是对象,都会占用内存,内存中对象越多,性能越差
2 事先指定所有的事件处理程序而导致dom访问次数,会延迟整个页面的交互的就绪事件.
所以:对事件处理程序过多问题的解决方案就是事件委托.
举个栗子
<ul id = 'ul1'>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
...
<li>100</li>
</ul>
如果咱们页面上有100个li标签,如果要实现点击li变成红色,我们虽然可以用for循环,给每个li添加事件,那这样就为它们添加了100个事件处理程序,若在一个复杂的web程序中,都使用这种方式,那结果就是数不清的添加事件处理.那么这里是极其浪费资源的.所以这里可以得到一个结论:
事件委托,最重要的功能就是提高程序运行效率.
既然出来了事件委托,那咱们讲讲事件委托的原理.先来个概念:事件流.
事件流分为
1.事件捕获
当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件
2.事件冒泡
当事件到达目标节点后,会沿着捕获阶段的路线原路返回。同样,所有经过的节点,都会触发对应的事件
那现在直接上代码,带大家来了解什么是事件捕获和事件冒泡
<div id = 'div1'>
爷爷
<div id = 'div2'>
父亲
<div id = 'div3'>
孙子
</div>
</div>
</div>
<style>
div{padding: 50px; color: white; font-size: 20px;}
#div1{background-color: orange;}
#div2{background-color: blue;}
#div3{background-color: red;}
<style>
例如,咱们都给这三个div同时绑定了点击事件,那我在点击孙子时,按常理来说,是不是也是点击了父亲和爷爷呢,所以呢,咱们点击了孙子的click事件,那么这个事件就会向dom树上传播,也就是这个顺序
div3>div2>div1>body>html>document.....
那么呢,这就是事件冒泡,而事件捕获正好相反,在事件捕获过程中,document首先接到click事件,然后沿着document向下,一直传播到事件的实际目标.也就是按着这个顺序
document>html>body>div1>div2>div3
但传统的事件的绑定没有办法实现事件捕获的,咱们的默认事件流还是事件冒泡!
事件冒泡:由里向外逐级向外触发(必须由父子关系的组件)(默认事件流)
事件捕获:由外向里逐级向外触发(必须由父子关系的组件) 传统的事件的绑定没有办法实现
好,这里有人问了,既然咱们讲的是事件委托,为什么这里要将事件流的事件冒泡和事件捕获呢.其实咱们要实现的事件委托原理就是事件冒泡!那接着来说咱们上述的案例,现在需求来了,如果要给100个,1000个li标签同时绑定onclick事件,咱们这里用最高效的方式进行绑定,没错,就是事件委托.
<ul id = 'ul1'>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
...
<li>100</li>
</ul>
要给这100个li标签绑定事件,当我们单击li时,当前被点击的li标签背景显示红色.同时呢,这里又产生了一个问题:父级那么多子元素,怎么区分事件本应该是哪个子元素的?答案是咱们的事件中有个event对象,而event对象里记录的有“事件源”,它就是发生事件的子元素。咱们在写的时候,这个获取event的事件源是有IE兼容性的. 在低版本中的获取是window.event.srcElement;而在咱们其他浏览器是可以直接通过event.target获取的,咱们一般的写法是
var target = event.target || window.event.srcElement;//短路操作
那咱们通过事件委托来实现
var oUl = document.getElementById("ul1");
//委托ul上的点击事件,将当前点击的li节点变成红色。
oUl.onclick = function(ev){
//获取事件对象短路操作,兼容IE
var e = ev || window.event;
//获取事件源 target 这里也要兼容IE
var target = e.target || window.event.srcElement;
//判断target是否符合要求的元素节点
if(target.tagName.toLowerCase() == "li"){
//将当前点击这个li节点变成红色
target.style.backgroundColor = 'red';
}
}
这里咱们就真真实实的实现了一个事件委托,而且,就只绑定了一个事件,把这个事件给了ul标签.咱们通过点击li,然后通过冒泡原理 子元素身上的事件会冒泡到父元素身上 那这里是不是比传统的实现方式方便了很多呢,而且节省了大量的内存资源.没有那么多事件处理程序了,这是对web程序的一个性能的优化.综上,可以总结出要实现事件委托,必须遵从的三个条件:
1、找要添加行为的节点的父节点或者祖先节点
2、将事件绑定在找到的父节点上
3、找到触发对象,判断是否符合要求,如果符合要求,进行后续操作。
其实事件委托的好处不仅止于此,再来个需求,在页面上给一个按钮,通过点击按钮,然后给ul标签新加一个ul标签.那这个新加的li标签,也要实现上面兄弟级一样的功能.传统事件中,咱们需要为新加的绑定事件,那不是非常的麻烦吗.
//为了给新加标签内容标识
var i = 6;
var oBtn = document.getElementById("btn1");
oBtn.onclick = function(){
//创建一个新的li标签
var newLi = document.createElement("li");
//给新加的标签添加内容
newLi.innerHTML = 111 * i++;
//将新加的li标签,添加到ul元素的末尾
oUl.appendChild(newLi);
}
我们这里通过事件委托来实现,上述新加的li标签,同样也享受li兄弟级的一样的功能.那就是后添加节点,拥有前面绑定好的函数。
事件委托的优点:
1.提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
2.动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
那今天的js事件委托就讲到这里了,欢迎各位大佬来喷,评论区留给你们