JavaScript事件流

 

1.概述

事件流:页面中接受事件的顺序。

IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流。

 

2、事件冒泡

IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

也就是说, click 事件首先在 <div> 元素上发生,而这个元素就是我们单击的元素。然后, click事件沿 DOM 树向上传播,在每一级节点上都会发生,直至传播到 document 对象。

所有现代浏览器都支持事件冒泡,但在具体实现上还是有一些差别。IE5.5 及更早版本中的事件冒泡会跳过 <html> 元素(从 <body> 直接跳到 document )。IE9、Firefox、Chrome 和 Safari 则将事件一直冒泡到 window 对象

3、事件捕获

  事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件。

虽然事件捕获是 Netscape Communicator 唯一支持的事件流模型,但 IE9、Safari、Chrome、Opera和 Firefox 目前也都支持这种事件流模型

尽管“DOM2 级事件”规范要求事件应该从 document 对象开始传播,但这些浏览器都是从 window 对象开始捕获事件的

IE9、Opera、Firefox、Chrome 和 Safari 都支持 DOM 事件流;IE8 及更早版本不支持 DOM 事件流

4、事件处理程序

(1)HTML事件处理程序

<input type="button" value="Click Me" onclick="alert('Clicked')" />

缺点:

 HTML 与 JavaScript 代码紧密耦合

(2)DOM0级事件处理程序

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
};
btn.onclick = null; //删除事件处理程序

 

优点:跨浏览器的优势,所有现代浏览器所支。缺点:DOM0 级对每个事件只支持一个事件处理程序。


(3)DOM2级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener()和 removeEventListener()

所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true ,表示在捕获阶段调用事件处理程序;如果是 false ,表示在冒泡阶段调用事件处理程序注意添加的事件类似为click,非onclick

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);

优点:使用 DOM2 级方法添加事件处理程序的主要好处是可以添加多个事件处理程序

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);

这里为按钮添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,因此首先会显示元素的 ID,其次会显示 "Hello world!" 消息。

通过 addEventListener() 添加的事件处理程序只能使用 removeEventListener() 来移除;移除时传入的参数与添加处理程序时使用的参数相同。

这也意味着通过 addEventListener() 添加的匿名函数将无法移除

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
// 这里省略了其他代码
btn.removeEventListener("click", function(){ // 没有用!
alert(this.id);
}, false);

以上代码不行。应该修改为:

var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
// 这里省略了其他代码
btn.removeEventListener("click", handler, false); // 有效!

IE9、Firefox、Safari、Chrome和 Opera 支持 DOM2 级事件处理程序。

(4)IE事件处理程序

IE 实现了与 DOM 中类似的两个方法: attachEvent() 和 detachEvent() 。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过attachEvent() 添加的事件处理程序都会被添加到冒泡阶段。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});

注意, attachEvent() 的第一个参数是 "onclick" ,而非 DOM 的 addEventListener() 方法中的 "click"

在 IE 中使用 attachEvent() 与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。在使用 DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用 attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
btn.attachEvent("onclick", function(){
alert("Hello world!");
});

这里调用了两次 attachEvent() ,为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是 "Hello world!" ,然后才是 "Clicked" 。

使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除

支持 IE 事件处理程序的浏览器有 IE 和 Opera

5、跨浏览器的事件处理程序

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;
}
}
};

addHandler() 和 removeHandler() 没有考虑到所有的浏览器问题,例如在 IE 中的作用域问题

此外还要注意,DOM0 级对每个事件只支持一个事件处理程序

6、更新2019.1.3 

还有DOM3事件流。DOM3事件流添加了更多的方法。如keydown等。

原文地址:https://www.cnblogs.com/mengfangui/p/8435316.html