概念:
- JavaScript高级程序设计 (简称JS高程) :事件代理 (事件委托) 利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
作用:
-
减少与dom的交互次数,提高代码性能。 (--代码性能--)
- 在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是要减少DOM操作;如果使用事件代理,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能。
- JS高程上关于代码优化中提到了:如果可能,在文档级别附加事件处理程序,这样可以处理整个页面的事件。
-
动态生成DOM元素时,可通过事件代理给新增的元素添加事件函数。
- 比如在异步获取后台数据加载页面时,直接给动态生成的DOM元素绑定事件函数可能需要在ajax交互时加入事件函数,这样往往会使得代码变得混乱,而使用事件代理则会非常方便。
原理:
- 事件冒泡:事件开始时由嵌套层次最深的节点开始接收,然后逐级向其父级节点传播。
- 例:页面中有 div>ul>li>p 的结构,当你 click 了 p 元素,click 事件首先在 p 元素上发生,然后,click 事件沿DOM树向上传播,分别在 li>ul>div 上发生,按照JS高程上的说明,最终会传播到 document 对象。
- 注:与事件冒泡对应的还有事件捕获。
- 事件代理:利用事件冒泡原理,把事件函数绑定在父级元素上,再指定需要执行函数的子元素执行事件函数;在触发事件时,事件会依次冒泡到父级元素,从而触发绑定在父级元素的事件函数。
- 对于事件代理原理的理解,阅读下面关于事件对象和具体用法的介绍后会更加清晰。
用法:
1.原生JS
-
事件对象:在触发DOM上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息,在执行事件处理程序时 event 对象会被传入;只有在事件处理程序执行期间,event 对象才会存在;一旦事件处理程序执行完成,event 对象就会被销毁;对于事件代理,这里重点介绍下 event 的几个属性。
- currentTarget :其事件函数当前正在处理事件的那个元素;如果感觉这个定义有点拗口,你可以暂且把 currentTarget 简单的理解为原生JS中事件函数内部的 this 。
- target :事件目标;即触发事件的实际目标。
- 这里用一个例子说明:假设页面中有 ul>li>p 的结构,然后点击 p 标签来执行下面代码(这里为方便阅读没有做兼容性处理,此代码需要在chrome浏览器下运行)
var ul = document.querySelector('ul'); var li = document.querySelector('li'); var p = document.querySelector('p'); ul.onclick = function(event) { console.log(this); // <ul>...</ul> console.log(event.currentTarget); // <ul>...</ul> console.log(event.target); // <p>...</p> }
从运行结果可以看到,当把事件函数绑定在父元素时,currentTarget 属性和函数内部的 this 都为绑定事件函数的父元素,而 target 属性的值则是我们想要触发事件的子元素。
具体用法:给父元素绑定事件函数,然后通过条件判断找到需要执行事件函数的元素。
页面结构如下:
<ul>
<li><p id="aaa">AAA</p></li>
<li><p id="bbb">BBB</p></li>
</ul>
JS代码如下:
var ul = document.querySelector('ul');
var li = document.querySelector('li');
var p = document.querySelector('p');
ul.onclick = function(e) {
// 兼容性处理
var e = e || window.event;
var target = e.target || e.srcElement;
switch (target.id){
case "aaa":
alert("AAA");
break;
case "bbb":
alert("BBB");
break;
default :
alert("未点击 p 标签");
break;
}
}
从测试结果可以看到,只在父元素上绑定一次事件函数,通过条件判断可以分别找到父元素下触发事件的子元素,然后分别进行操作。
2.jQuery
- jQuery 的 on 方法中已经封装好了事件代理的功能,而且事件函数内部的 this 直接指向的就是被指定的元素。
// on 的3个参数 1.事件类型 2.给事件指定的元素 3.事件函数
$("div").on("click", "p", function () {
alert("p");
console.log(this); // p
})
注意 jQuery 的 on 方法中 this 直接指向的就是触发事件的子元素 p 。
结尾:
- 原生JS中的一些事件如 onmouseover 存在一些不好用的问题,同时通过 target 等属性进行筛选又需要写不少条件判断的代码,相比下jQuery 的 on 方法则封装得简单直接,但是这里并非单纯推荐使用第三方库,实际应用中要根据具体需求做选择。
会同步在 kabumie 的 github 空间上