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


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

一、事件流

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

事件冒泡

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

<!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事件,如下:

<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”。

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

事件捕獲

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

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

<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級事件處理)

點擊<div>,將先輸出“body”,再輸出“div”。

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”。

 

二、事件處理程序

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

HTML事件處理程序

通過將事件作為HTML元素的屬性來實現,包含以下兩種方法:

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

辦公資源網址導航 https://www.wode007.com

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM