事件流
事件流描述了页面接收事件的顺序。
事件冒泡
IE 事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
在点击页面中的
元素后,click 事件会以如下顺序发生:
(1) <div>
(2) <body>
(3) <html>
(4) document
事件处理程序
事件意味着用户或浏览器执行的某种动作。比如,单击(click)、加载(load)、鼠标悬停(mouseover)。
为响应事件而调用的函数被称为事件处理程序(或事件监听器)。
事件处理程序的名字以"on"开头,因此click 事件的处理程序叫作onclick,而load 事件的处理程序叫作onload。
DOM2 事件处理程序
DOM2 Events 为事件处理程序的赋值和移除定义了两个方法:addEventListener()和remove-EventListener()。
这两个方法暴露在所有DOM 节点上,它们接收3 个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false(默认值)表示在冒泡阶段调用事件处理程序。
//为按钮添加了会在事件冒泡阶段触发的onclick 事件处理程序(因为最后一个参数值为false)
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
使用DOM2方式的主要优势是可以为同一个事件添加多个事件处理程序。
//给按钮添加了两个事件处理程序。多个事件处理程序以添加顺序来触发,因此前面的代码会先打印元素ID,然后显示消息“Hello world!”。
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
btn.addEventListener("click", () => {
console.log("Hello world!");
}, false);
通过addEventListener()添加的事件处理程序只能使用removeEventListener()并传入与添加时同样的参数来移除。
这意味着使用addEventListener()添加的匿名函数无法移除
//第二个参数与传给addEventListener()的完全不是一回事,所以会失效
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
// 其他代码
btn.removeEventListener("click", function() { // 没有效果!
console.log(this.id);
}, false);
只有传入同一个函数才会有效
let btn = document.getElementById("myBtn");
let handler = function() {
console.log(this.id);
};
btn.addEventListener("click", handler, false);
// 其他代码
btn.removeEventListener("click", handler, false); // 有效果!
IE 事件处理程序
IE 实现了与DOM 类似的方法,即attachEvent()和detachEvent()。
这两个方法接收两个同样的参数:事件处理程序的名字和事件处理函数。
注:attachEvent()添加的事件处理程序会添加到冒泡阶段(相当于addEventListener的第三个参数为false)
与使用addEventListener()一样,使用attachEvent()方法也可以给一个元素添加多个事件处理程序
//与DOM 方法不同,这里的事件处理程序会以添加它们的顺序反向触发。换句话说,在点击例子中的按钮后,控制台中会先打印出"Hello world!",然后再打印"Clicked"。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function() {
console.log("Clicked");
});
btn.attachEvent("onclick", function() {
console.log("Hello world!");
});
只要传给detachEvent()方法相同的函数引用,就可以移除。
var btn = document.getElementById("myBtn");
var handler = function() {
console.log("Clicked");
};
btn.attachEvent("onclick", handler);
// 其他代码
btn.detachEvent("onclick", handler);
跨浏览器事件处理程序
手动编写跨浏览器事件处理程序:
addHandler()方法:根据需要分别使用DOM0 方式、DOM2 方式或IE 方式来添加事件处理程序
addHandler()方法接收3 个参数:目标元素、事件名和事件处理函数。
//EventUtil 对象上添加一个方法
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
调用
let btn = document.getElementById("myBtn")
let handler = function() {
console.log("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// 其他代码
EventUtil.removeHandler(btn, "click", handler);