事件模型
浏览器的事件模型,就是通过监听函数对事件做出反应。事件发生后,浏览器监听到了这个时间,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
JavaScript有三种方法可以为事件绑定监听函数。
1.HTML的on-属性
HTML语言允许在元素的属性中,直接定义某些事件的监听代码
<body onload="doSomething()">
<div onclick="console.log('触发事件')">
但项目实践中我们不会这么写,因为违反了HTML与JavaScript代码相分离的原则。两者写在一起,不利于代码分工。
2.元素节点的事件属性
元素节点对象的事件属性,同样可以指定监听函数。
window.onload = doSomething;
div.onclick = function (event) {
console.log('触发事件');
}
这种方法的缺陷在于:同一个事件只能定义一个监听函数,i.e.如果定义两次onclick属性,后一次定义会覆盖前一次。所以同样不建议使用。
3.EventTarget.addEventListener()
所有DOM节点实例都有addEventListener方法,用来为该节点定义事件的监听函数。
window.addEventListener('load', doSomething, false) // 参数false指定在冒泡阶段监听事件
实践中推荐使用该方法,这种方法的优点在于:
- 同一个事件可以添加多个监听函数
- 能够指定在哪个阶段触发监听函数(捕获还是冒泡阶段)
- 除了DOM节点,其他对象(比如
window、XMLHttpRequest等)也有这个接口,它等于是整个JavaScript统一的监听函数接口。
this的指向
三种方法监听函数内部的this指向触发事件的那个元素节点。
监听函数的两个属性:target和currentTarget有区别。
e.target——指用户操作的元素e.currentTarget——指监听的元素,这也是this的指向 举例:
div > span{文字},用户点击文字e.target就是spane.currentTarget就是div
事件的传播
根据W3C在2002年发布的标准,浏览器应该同时支持两种调用顺序——先捕获,后冒泡。具体来说:
- 第一阶段:从
window对象传导到目标节点(上层传到底层,外层传到内层),定义为“捕获阶段”(capture phase) - 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)
- 第三阶段:从目标节点传导回
window对象(从底层传回上层,从内层传到外层),成为“冒泡阶段”(bubbling phase)
事件委托
事件委托也叫做事件代理(delegation)。由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父结点上,由父节点的监听函数统一处理多个子元素的事件。这样做的好处是:
- 节省内存
- 同时也可以监听动态元素
如果希望事件到某个节点为止,不再传播,可以使用事件对象的
stopPropagation方法。
// 事件传播到 p 元素后,就不再向下传播了
p.addEventListener('click', function (event) {
event.stopPropagation();
}, true);
// 事件冒泡到 p 元素后,就不再向上冒泡了
p.addEventListener('click', function (event) {
event.stopPropagation();
}, false);
需要注意stopPropagation方法只能阻止事件的传播,不能取消事件,如果想要彻底取消该事件,不再触发后面所有的监听函数,可以使用stopImmediatePropagation方法。
p.addEventListener('click', function (event) {
event.stopPropagation();
console.log(1);
});
p.addEventListener('click', function(event) {
// 会触发
console.log(2);
});
p.addEventListener('click', function (event) {
event.stopImmediatePropagation();
console.log(1);
});
p.addEventListener('click', function(event) {
// 不会被触发
console.log(2);
});
*资料来源:[网道教程](https://wangdoc.com/javascript/events/model.html)*