一、如何让 DOM 节点监听事件
事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。
DOM 节点的事件操作(监听和触发),都定义在 EventTarget接口。所有节点对象都部署了这个接口。
该接口主要提供三个实例方法:
- 绑定事件的监听函数:
addEventListener() - 移除事件的监听函数:
removeEventListener() - 触发事件:
dispatchEvent()
EventTarget.addEventListener()
target.addEventListener(type, listener[, useCapture]);
用于在当前节点或对象上,定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。
接受三个参数:
type:事件名称,大小写敏感listener:监听函数。事件发生时,会调用该监听函数。useCapture:该参数可选,布尔值。true表示监听函数将在捕获阶段触发。默认值为false(监听函数只在冒泡阶段被触发)。
第二个参数除了监听函数,还可以是一个具有handleEvent方法的对象,效果与监听函数一样。
第三个参数除了布尔值useCapture,还可以是一个监听器配置对象,定制事件监听行为:
element.addEventListener('click', function(event){
// 只执行一次的代码
}, {once: true});
addEventListener()方法可以为同一对象的同一事件,添加多个不同的监听函数,这些函数将按照添加顺序触发,即先添加先触发。但如果为同一事件多次添加相同的监听函数,该函数只会执行一次,多余的添加将自动被去除。
监听函数内部的this,指向当前事件所在的那个对象。
// HTML 代码如下
// <p id="para"> hello </p>
var para = document.getElementById('para');
para.addEventListener('click', function(e){
console.log(this.nodeName); // this 指向事件所在的对象 para
});
二、事件模型
浏览器的事件模型,就是通过监听函数(listener)对事件做出反应。事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
1. 事件的传播
一个事件发生后,会在子元素和父元素之间传播(propagation),分为捕获阶段(capture phase),目标阶段(target phase),冒泡阶段(bubbling phase)。
这种三阶段的传播模型,使得同一个事件会在多个节点上触发。
简而言之就是,事件捕获是从外向内找监听函数,事件冒泡是从内向外找监听函数。
2. 如何取消冒泡
捕获阶段不可取消,但冒泡可以取消。
e.stopPropagation()可以中断冒泡,浏览器不再向上走,一般用于封装某些独立的组件。
三、事件委托(事件代理)
事件代理(delegation):由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数来统一处理多个子元素的事件。
即利用事件冒泡的机制,把里层所需要响应的事件绑定到外层。
var ul = document.querySelector('ul');
ul.addEventListener('click', function (event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});
上面代码中,click事件的监听函数定义在<ul>节点上,它处理的是子节点<li>的click事件。
这样做的好处是,不用在每个<li>节点上定义监听函数,只要在父节点上定义一个监听函数,就能处理多个子节点的事件,而且以后再添加子节点,监听函数依然有效。
另一种场景是,需要监听目前并不存在的元素的点击事件,同样也是把监听函数定义在父节点上,等点击后,冒泡阶段再判断是不是我想要监听的元素即可。
所以事件委托的优点:1. 省监听数(省内存);2. 可以监听动态元素。
参考链接
本文只是作为个人学习笔记整理记录。