比如说当我们给元素设置点击事件,点击时,由外到里会经历捕获阶段、目标阶段、冒泡阶段,相应的,会触发路径元素上的事件。
捕获阶段 概念:
事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。
目标阶段 概念:
事件到达目标节点时,就到了目标阶段,事件在目标节点上被触发。
冒泡阶段 概念:
事件在目标节点上触发后,不会终止,一层层向上冒,回溯到根节点。
segmentfault:浏览器事件机制中 事件触发的三个阶段
我着重提一下 HTML DOM 的 addEventListener()
方法。在我们给元素添加事件时常用到这个方法。它主要有三个参数:
- event 事件名 必须
- function 处理函数 必须
- useCapture 指定事件是否在捕获或冒泡阶段执行。可选。布尔值。true - 事件在捕获阶段执行;false 默认,事件在冒泡阶段执行。
进入正文。
事件委托应用场景大多是,当有多个DOM需要被监听,如果给每一个DOM都添加事件监听,可能会影响系统的性能;但如果使用事件委托,通过确定事件绑定元素 e.currentTarget
与事件源 e.target
,就能简化很多代码。比如说把监听函数绑定到父容器上,点击事件源,给事件源进行单独的操作。(假设事件被命名为e)
那什么叫事件委托呢?
事件委托还有一个名字叫事件代理。JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
所以说,事件委托就是委托它们父级代为执行事件。另外,事件委托的原理是事件冒泡机制。
博客园:js中的事件委托或是事件代理详解
正如下面这个例子,当元素嵌套时,点击儿子div,根据冒泡机制,从儿子节点,一层一层往外执行,所以,执行顺序为 儿子—>父亲—>祖父。
<div id="grandfather">
祖父
<div id="father">
父亲
<div id="son">儿子</div>
</div>
</div>
<script>
var grandfather=document.querySelector("#grandfather");
var father=document.querySelector("#father");
var son=document.querySelector("#son");
grandfather.addEventListener("click",function(e){
console.log("祖父");
})
father.addEventListener("click",function(e){
console.log("父亲");
})
son.addEventListener("click",function(e){
console.log("儿子");
})
</script>
如果,我把grandfather绑定的addEventListener()的第三个参数改成true,那么事件执行顺序会发生改变,应该变成 祖父—>儿子—>父亲。因为祖父在捕获阶段就被执行了。
grandfather.addEventListener("click",function(e){
console.log("祖父");
},true)
那么如果现在,我们只给最外层的父元素即祖父节点添加事件,将事件委托给祖父节点,就可以通过事件源的方式,来处理我们所点击的目标元素。
grandfather.addEventListener("click",clickHandler);
function clickHandler(e){
console.log("事件源:",e.target.getAttribute('id'));
console.log("绑定的事件元素:",e.currentTarget);
}
当我点击父亲时,后台打印的事件源是我点击的父亲节点的相关信息,但是我绑定的元素依然是最外层祖父节点。
总之,事件委托的优点还是很多的,能够减少事件注册,节省内存占用,提高性能;如果有新增的元素的话,也不用再重新给父元素绑定事件,实现了动态绑定事件。