概念
JavaScript高级程序设计里解释:对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,指指定一个事件处理程序,就可以管理某一类型的所有事件。简单来说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序,如li、button、单选按钮radio等。
为什么要用事件委托?
比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能。
例子1
<style>
.palette {
margin: 0;
padding: 0;
list-style: none;
}
.palette li {
width: 40px;
height: 40px;
border: 1px solid #000;
cursor: pointer;
}
</style>
</head>
<body>
<ul class="palette">
<li style="background-color:crimson"></li>
<li style="background-color:bisque"></li>
<li style="background-color:blueviolet"></li>
<li style="background-color:coral"></li>
<li style="background-color:chartreuse"></li>
<li style="background-color:darkolivegreen"></li>
<li style="background-color:cyan"></li>
<li style="background-color:#194738"></li>
</ul>
<p class="color-picker"></p>
如代码所示,在一组无序列表中,给每个li标签都添加了border边框,并且设定了边框背景颜色,效果图如下
题目要求如下:点击某一个 Li 标签时,将 Li 的背景色显示在 P 标签内,并将 P 标签中的文字颜色设置成 Li 的背景色。
基础思路是:利用for循环为每个节点都添加DOM操作
var list = document.querySelectorAll("li");
for (var i = 0, len = list.length; i < len; i++) {
list[i].onclick = function(e) {
var t = e.target;
var c = t.style.backgroundColor;
var p = document.getElementsByClassName("color-picker")[0]
p.innerHTML = c;
e.target.style.backgroundColor=p.style.color;
p.style.color = c;
}
}
这样,就为每个li都添加了onclick事件
补充说明:有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如 event, evt或简单的 e。 这被称为 事件对象 ,它被自动传递给事件处理函数,以提供额外的功能和信息。
事件对象 e 的 target属性始终是事件刚刚发生的元素的引用,在本个例子中为被点中的li标签。
进阶:那么我们用事件委托的方式做又会怎么样呢?
这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发,不怕,我们有绝招:
事件对象完全可以返回目标节点,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,判断是点击了ul还是li。代码如下:
var list = document.querySelectorAll("li");
var nUl=document.querySelector('ul');
/* 事件委托处理 */
nUl.onclick=function(e){
var t = e.target;
if(t.nodeName=="LI"){
var p = document.getElementsByClassName("color-picker")[0];
var c = t.style.backgroundColor;
p.innerHTML = c;
e.target.style.backgroundColor=p.style.color;
p.style.color = c;
}
}
修改过后,只有点击li才会触发事件了!且每次只会执行一次dom操作,优化了性能。