js事件冒泡和事件捕獲詳解

Javascript與HTML之間的交互是經過事件實現。javascript

1、事件流

事件,是文檔或瀏覽器窗口中發生的一些特定的交互瞬間。事件流,描述的是頁面中接受事件的順序。IE9,chrome,Firefox,Opera,Safari均實現了DOM2級規範中定義的標準DOM事件,而IE8和IE8如下版本仍然保留專有的事件處理方式。css

事件冒泡

事件冒泡是由IE開發團隊提出來的,即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播。html

複製代碼
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Event Bubbling Example</title>
    </head>
    <style type="text/css">
        #myDiv{
            width:100px;
            height:100px;
            background-color:#FF0000;
        }
    </style>
    <body>
        <div id="myDiv"></div>
    </body>    
</html>
複製代碼

 

當用戶點擊了<div>元素,click事件將按照<div>—><body>—><html>—>document的順序進行傳播。若在<div>和<body>上都定義了click事件,以下:java

複製代碼
<script type="text/javascript">
        var div=document.getElementById("myDiv");
        div.onclick=function(event){
            alert("div");
        };
        document.body.onclick=function(event){
            alert("body");
        };    
</script>
複製代碼

點擊<div>,將先輸出「div」,再輸出「body」。chrome

IE9,chrome,Firefox,Opera,Safari都支持事件冒泡,並將事件冒泡到window對象。瀏覽器

事件捕獲

事件捕獲是由Netscape Communicator團隊提出來的,是先由最上一級的節點先接收事件,而後向下傳播到具體的節點。當用戶點擊了<div>元素,採用事件捕獲,則click事件將按照document—><html>—><body>—><div>的順序進行傳播。函數

若在<div>和<body>上都定義了click事件,以下:post

複製代碼
<script type="text/javascript">
        var div=document.getElementById("myDiv");    
        div.addEventListener("click",function(event){
            alert("div");
        },true);
        document.body.addEventListener("click",function(event){
            alert("body");
        },true);
        
    </script>
複製代碼

(注:addEventListener具體使用見本文DOM2級事件處理)ui

點擊<div>,將先輸出「body」,再輸出「div」。this

IE9,chrome,Firefox,Opera,Safari都支持事件捕獲,可是IE8和IE8如下的版本只支持事件冒泡。儘管DOM2規範要求事件應該從document對象開始傳播,可是如今的瀏覽器實現都是從window對象開始捕獲事件。

DOM事件流

"DOM2級事件」規定的事件流包含三個階段:事件捕獲階段,處於目標階段和事件冒泡階段。首先發生的是事件捕獲,而後是實際的目標接收到事件,最後階段是冒泡階段。以上面的HTML頁面爲例,單擊<div>元素將按照下圖觸發事件:

 

若在<div>和<body>上都定義了click事件,以下:

複製代碼
<script type="text/javascript">
        var div=document.getElementById("myDiv");    
        div.onclick=function(event){
            alert("div");
        };
        document.body.addEventListener("click",function(event){
            alert("event bubble");
        },false);
        document.body.addEventListener("click",function(event){
            alert("event catch");
        },true);
        
    </script>
複製代碼

點擊<div>,將先輸出「event catch」,再輸出「div」,最後輸出「event bubble」。

2、事件處理程序

事件是用戶或瀏覽器自身執行的某種動做,而響應某個事件的函數叫作事件處理程序。HTML事件處理程序、DOM0級事件處理程序和IE事件處理程序均以「on」開頭,DOM2級事件處理程序不須要加「on」。

HTML事件處理程序

經過將事件做爲HTML元素的屬性來實現,包含如下兩種方法:

1
< input  type="button" value="confirm" onclick="alert('confirm')" />

或者調用其餘地方定義的腳本:

<script type="text/javascript">
        function showMessage() {
            alert("confirm");
        }
</script>
<input type="button" value="confirm" onclick="showMessage()"/>

(注:函數定義必須放在調用以前)

DOM0級事件處理程序

 經過Javascript指定事件處理程序的傳統方式,全部瀏覽器均支持。每一個元素(包括window,document)都有本身的事件處理程序屬性,可是必須在DOM節點加載完以後纔會有效。以下所示:

<script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.onclick = function(event) {
            alert("div");
        };
    </script>

使用DOM0級方法指定的事件處理程序被認爲是元素的方法,在元素的做用域中運行。this引用當前元素,以下:

<script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.onclick = function(event) {
            alert(this.id);
        };
    </script>

輸出「myDiv」。

刪除經過DOM0級方法指定的事件處理程序:div.onclick=null;

DOM2級事件處理程序

IE9,chrome,Firefox,Opera,Safari均實現了DOM2級事件處理程序,綁定事件方法addEventListener()接收三個參數:事件名稱,事件處理函數和一個布爾值。布爾值爲true,則表示在捕獲階段調用事件處理程序;若是爲false,則表示在冒泡階段調用事件處理程序。addEventListener容許在同一個元素上添加多個事件處理程序,以下所示:

複製代碼
    <script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.addEventListener("click", function(event) {
            alert("event bubble");
        }, false);
        div.addEventListener("click", function(event) {
            alert("event catch");
        }, true);
    </script>
複製代碼

先輸出「event bubble」,後輸出「event catch」,說明addEvenListener綁定的處理程序執行順序和綁定順序相同。

經過DOM2級事件處理程序指定的方法,this也引用當前元素,以下:

<script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.addEventListener("click", function(event) {
            alert(this.id);
        }, false);
    </script>

輸出「myDiv」。

刪除DOM2級事件處理程序,採用removeEventListener(),刪除時傳入的參數必須和綁定時傳入的參數相同,不能傳入匿名函數。以下所示:

複製代碼
<script type="text/javascript">
        var div = document.getElementById("myDiv");
        var handler=function(event){
            alert("delete");
        };        
        div.addEventListener("click",handler,false);
        div.removeEventListener("click",handler,false);
    </script>
複製代碼

IE事件處理程序

IE8和IE8如下的版本不支持addEventListener(),而是採用attachEvent()來實現事件綁定。目前只有IE和Opera支持attachEvent()。IE9支持addEventListener(),同時也兼容IE8的attachEvent()方法,可是IE9和IE8對attachEvent()的實現有點不一樣。以下所示:

複製代碼
    <script type="text/javascript">
        var div = document.getElementById("myDiv");
        div.attachEvent("onclick", function(event) {
            alert("1");
        });
        div.attachEvent("onclick", function(event) {
            alert("2");
        });
    </script>
複製代碼

IE9和IE10先輸出「1」,再輸出「2」,而IE8和IE7先輸出「2」,再輸出「1」。

刪除IE事件處理程序,採用detachEvent(),刪除時傳入的參數必須和綁定時傳入的參數相同,不能傳入匿名函數。以下所示:

複製代碼
<script type="text/javascript">
        var div = document.getElementById("myDiv");
        var handler = function(event) {
            alert("delete");
        };
        div.attachEvent("onclick",handler);
        div.detachEvent("onclick",handler);
    </script>
複製代碼

總結:attachEvent()採用冒泡方式,而addEventListener()能夠採用冒泡或事件捕獲方式。

先按由上往下的順序執行事件捕獲的執行程序,再執行目標元素的執行程序,最後按由下往上的順序執行冒泡事件。代碼以下所示:

複製代碼
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Event Bubbling Example</title>
    </head>
    <style type="text/css">
        #child {
            width: 100px;
            height: 100px;
            background-color: #FF0000;
        }
    </style>
    <body>
        <div id="parent">
            <div id="child"></div>
        </div>
    </body>
    <script type="text/javascript">
        var parent = document.getElementById("parent");
        var child = document.getElementById("child");
        child.onclick = function(event) {
            alert("child");
        };
        document.body.addEventListener("click", function(event) {
            alert("body:event bubble");
        }, false);
        parent.attachEvent("onclick", function(event) {
            alert("parent:event bubble");
        });
        document.body.addEventListener("click", function(event) {
            alert("body:event catch");
        }, true);
        parent.addEventListener("click", function(event) {
            alert("parent:event catch");
        }, true);
    </script>
</html>
複製代碼

輸出順序:body:event catch—>parent:event catch—>child—>parent:event bubble—>body:event bubble

相關文章
相關標籤/搜索