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);
以上是什麼是JavaScript事件流及事件處理程序詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!