JS与HTML之间的交互通过事件实现。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用监听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式,支持页面的行为与页面的外观之间的松散耦合。
事件流
事件流描述的是从页面中接受事件的顺序。
事件冒泡
事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的结点(文档)。以下面HTML页面为例,如果你点击了页面中的按钮,那么”click”事件会按照< button>、< body>、< html>、document的顺序传播。换句话说,事件冒泡指的就是事件从底层触发事件的元素开始沿着DOM树向上传播,直到document对象。
<html> <head> <title>Test</title> </head> <body> <button id="myBtn">A Btn</button> </body> </html>
事件捕获
与事件冒泡的思路相反,事件捕获的思想是不太具体的节点应该更早地接收到事件,最具体的结点应该最后才接收事件。同样还是上面那个例子,点击页面中的按钮之后,”click”事件会按照document、< html>、< body>、< button>的顺序传播。换句话说,事件捕获就是指事件从document对象开始沿着DOM树向下传播,直到事件的实际目标元素。
DOM事件流
“DOM2级事件”规定的事件包括三个阶段: 事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
还是以之前的点击按钮为例,在DOM事件流中,捕获阶段,”click”事件从document开始向下传递到body元素(注意,实际目标button在捕获阶段不会接收到事件)。目标阶段,button元素接收到”click”事件。最后,冒泡阶段,事件又被传播回文档。
事件处理程序
事件是用户或浏览器自身执行的某种动作,而响应某个事件的函数就叫做事件处理程序或事件侦听器。
HTML事件处理程序
这里的HTML事件处理程序指的是直接在HTML元素里面通过特性(attribute)定义的事件处理程序,请看下面的代码示例。这样是定的事件处理程序会创建一个封装着元素属性值的函数,this值等于事件的目标元素。通过这种方法指定事件处理程序存在不少缺点,不推荐使用。
<button onclick="alert('HaHa~')">Btn-1</button> <button onclick="alert('event.type')">Btn-2</button> <button onclick="handler()">Btn-3</button> <script type="text/javascript"> function handler() { alert("Haha~"); } </script>
DOM0级事件处理程序
通过JS指定事件处理程序的传统方式就是将一个函数赋值给一个事件处理程序属性,请看下面代码示例。通过这种方式指定的事件处理程序是在元素的作用域中运行,this引用的是当前元素。这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。若要删除事件,直接令onclick的值为空即可。
var btn = document.getElementById("myBtn"); btn.onclick = function() { console.log("this.id"); // "myBtn" }; // 删除事件处理程序 btn.onclick = null;
DOM2级事件处理程序
“DOM2级事件”定义了两个方法用于指定和删除事件处理程序,addEventListener()和removeEventListener()。所有DOM节点中都包含这两个方法。这两个方法都接收3个参数,要处理的事件、处理函数、布尔值。最后的布尔值为true时表示在捕获阶段调用事件处理程序,为false时表示在冒泡阶段调用处理程序。与DOM0级方法一样,这里添加的事件处理程序也是在其依附的元素的作用域中运行。DOM2级方法添加事件处理程序的优势是可以添加多个事件处理程序。这些事件处理程序会按照它们被添加的顺序触发。下面是代码示例:
var btn = document.getElementById("myBtn"); // 添加,触发点击事件时先输出"myBtn"再输出"HaHa~" btn.addEventListener("click", function() { console.log(this.id); }, false); btn.addEventListener("click", function() { console.log("HaHa~"); }, false);
通过addEventListener()添加的事件只能通过removeEventListener()来删除。删除时传入的参数与添加时使用的参数应该保持一致。这也意味着通过addEventListener()添加的匿名函数将无法删除,因为无法将添加时传递的匿名函数传给removeEventListener(),即便在删除的时候写了一个一模一样的函数,但此时这个函数只是一个新的匿名函数。请看下面代码示例:
var btn = document.getElementById("myBtn"); // 无法删除匿名函数 btn.addEventListener("click", function() { console.log(this.id); }, false); btn.removeEventListener("click", function() { console.log(this.id); }, false); // 正确的添加和删除方式 function handler() { console.log(this.id); } btn.addEventListener("click", handler, false); btn.removeEventListener("click", handler, false);
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候才将事件处理程序添加到捕获阶段。JS高级程序设计上给出的建议是,如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。
IE事件处理程序
IE实现了与DOM中类似的两个方法: attachEvent()和deleteEvent()。这两个方法接收两个参数,事件处理程序名称和事件处理程序。注意,第一个参数是事件处理程序名称而不是事件名称,也就是说在注册点击事件的处理程序时应该传入”onclick”而不是”click”,这里跟DOM的方法有些差别。另外,这两个方法注册的事件处理程序是在全局作用域中运行而不是元素作用域,this的值指向window。还有一点需要特别小心,通过attachEvent()方法也可以添加多个事件处理程序,但是它们的执行顺序却不是按照它们被添加的顺序,而是完全相反,跟DOM方法截然不同。突然觉得IE真的特别反人类~~~下面是代码示例:
var btn = document.getElementById("myBtn"); function handler1() { // ... } function handler2() { // ... } // 添加,触发点击事件时先执行handler2再执行handler1 btn.attachEvent("onclick", handler1); btn.attachEvent("onclick", handler2); // 删除 btn.deleteEvent("onclick", handler1); btn.deleteEvent("onclick", handler2);
Atas ialah kandungan terperinci 什么是JavaScript事件流及事件处理程序详解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!