DOM事件
触发的三个阶段
1、捕获阶段:事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到到达目标节点。
2、目标阶段:事件到达了目标节点时,事件在目标节点上触发。
3、冒泡阶段:事件在目标节点上触发后,不会终止,一层层向上冒泡,回溯到根节点。
注意:事件发生的时候,要经过事件的三个阶段,我们常常使用的是事件冒泡阶段,而其他两个阶段不能人为干预。
EventTarget接口
EventTarget.addEventListener()
绑定事件的监听函数
target.addEventListener(type, listener[, useCapture]);
// type:事件名称
// listener:监听函数。事件发生时,调用。
// useCapture:布尔值,默认值为false(只在冒泡阶段触发)。为true(在捕捉阶段也触发)
var button = document.getElementById('btn');
button.addEventListener('click',function(){
console.log('1');
},false)
注:第二个参数除了监听函数,还可以是一个具有handleEvent方法的对象。
第三个参数除了布尔值,还可以是一个属性配置对象。
EventTarget.removeEventListener()
移除事件的监听函数
参数与addEventListener一致。
注:移除失败可能原因:监听函数必须是addEventListener方法添加的监听函数,而且在同一个元素节点。
// 失败 监听函数不一致
div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);
// 失败 第三个参数不一致
element.addEventListener('mousedown', handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false);
EventTarget.dispatchEvent()
在当前节点触发指定事件,从而触发监听函数的执行。
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event); // 触发这个事件
绑定监听函数的三种方法
HTML的on- 属性
<body onload="doSomething()">
<div onclick="console.log('触发事件')">
一旦指定的事件发生,on-
属性的值是原样传入 JavaScript 引擎执行。因此如果要执行函数,不要忘记加上一对圆括号。
只在冒泡阶段触发。
不推荐使用,html代码和js代码写在一起了,不利于代码分工。
元素节点的事件属性
window.onload = doSomething; // 与上面一种方法的差异,它的值是函数名。
div.onclick = function (event) {
console.log('触发事件');
};
只在冒泡阶段触发
不推荐使用,同一事件只能定义一个监听函数。
EventTarget.addEventListener()
优点:同一个事件可以添加多个监听函数; 能指定在哪个阶段触发监听函数; 除了DOM节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,它等于是整个 JavaScript 统一的监听函数接口。
事件的传播
三种阶段的传播模型,使得同一个事件会在多个节点触发
例子:
<div>
<p>点击</p>
</div>
var phases = {
1: 'capture',
2: 'target',
3: 'bubble'
};
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);
function callback(event) {
var tag = event.currentTarget.tagName;
var phase = phases[event.eventPhase];
console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}
// 点击以后的结果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'
上面代码表示,click
事件被触发了四次:<div>
节点的捕获阶段和冒泡阶段各1次,<p>
节点的目标阶段触发了2次。
事件传播的最上层对象是window
,接着依次是document
,html
(document.documentElement
)和body
(document.body
)。也就是说,上例的事件传播顺序,在捕获阶段依次为window
、document
、html
、body
、div
、p
,在冒泡阶段依次为p
、div
、body
、html
、document
、window
。
事件的代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
stopPropagation
事件传播到某个节点为止不再传播。但只会阻止事件的传播,不能阻止改时间触发其他click事件的监听函数。也就是说不能彻底取消click事件。
// 在冒泡阶段阻止事件传播
p.addEventListener('click',function(event) {
event.stopPropagation();
},false)
p.addEventListener('click', function (event) {
event.stopPropagation();
console.log(1);
});
p.addEventListener('click', function(event) {
// 会触发
console.log(2);
});
stopImmediatePropagation
彻底取消该事件,不再触发事件所有的监听函数。
p.addEventListener('click', function (event) {
event.stopImmediatePropagation();
console.log(1);
});
p.addEventListener('click', function(event) {
// 不会被触发
console.log(2);
});