溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中如何實現事件冒泡與時間捕獲

發布時間:2021-12-24 09:38:11 來源:億速云 閱讀:149 作者:小新 欄目:web開發

小編給大家分享一下JavaScript中如何實現事件冒泡與時間捕獲,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

一、事件冒泡與事件捕獲

當我們在Web頁面單擊某一個元素的時候,比如某個p元素。仔細想想,我們單擊的不僅僅是這一個p元素,一同被單擊的還有以該p為圓心的同心圓元素,比如元素的父,外層body、body的父元素html還有外層的document。事件在這些嵌套的元素之間的傳播稱為事件流。

  • 1、事件冒泡

  • 2、事件捕獲

1、事件冒泡

IE的事件流稱為事件冒泡,事件從最具體的元素開始,逐級向上傳播。我們使用DOM0添加的事件處理程序就是在事件冒泡階段被處理的。例如:

<html>
  <head>
    <script type="text/javascript">

      window.onload = bubblingHandle;      function bubblingHandle() {
          //內層p處理程序
          document.getElementById("inner").onmousedown     = function() {
              alert("inner p");
          }          //外層p處理程序
          document.getElementById("outer").onmousedown = function() {
              alert("outerp");
          }

          document.onmousedown = function() {
              alert("document");
          }
      } 
      -->    </script>
  </head>
  <body>
    <p id="outer" style="background-color:black; padding: 15px;">
        <p id="inner" style="background-color:white; padding: 5px;"></p>
    </p>
  </body></html>

當點擊內層的白色p時,會依次顯示:

inner p
outer p
document

事件捕獲

網景提出的事件流稱為事件捕獲,其與IE幾乎相反。事件首先由最不具體的元素接收,然后逐級向具體節點傳播。

二、DOM0級事件處理

事件,由WEB頁面中發生的一些特定行為觸發。比如在某個頁面元素上按下鼠標左鍵,按下鍵盤某個按鍵,某對象獲得或丟失焦點時均會觸發對應的事件。JavaScript和HTML的交互就是通過事件來實現的。我們使用事件偵聽器對事件進行“注冊”,事件發生時便執行相應的代碼。

DOM0級事件處理程序以其簡單、跨瀏覽器支持的特點,至今仍為所有瀏覽器支持。

  • 通過DOM0級方法指定事件處理程序

  • 事件處理程序中的this

  • 通過DOM0級方法刪除事件處理程序

通過DOM0級方法指定事件處理程序

通過DOM0級方法指定事件處理程序方法很簡單,首先取得一個要操作元素的引用,然后接將一個函數賦值給該元素的對應事件處理程序屬性。(每個元素包括window和document都擁有自己的事件處理程序屬性。)注意,這種方法添加的事件處理程序將在事件流的冒泡階段被處理。

有關事件處理程序屬性,有以下幾點需要說明:

1、事件處理程序屬性全部小寫,以”on”開頭,后面跟事件類型:

onclick  //單擊鼠標
onload  //圖像或頁面載入完成
onmouseover  //將鼠標移動到某元素上面
onmousemove  //移動鼠標
onfocus  //對象獲得焦點

2、每個元素如img、a、input、form包括window和document都擁有自己的事件處理程序屬性。如:

document.getElementById("btn1").onclick  //btn1上單擊鼠標
document.getElementById("img1").onmouseover  //鼠標移動到img1
document.getElementById("img1").onmerror  //img1圖像無法載入

接下來,給事件處理程序屬性賦值即可完成事件處理程序方法的指定。例如,當鼠標移動到”img1”上時,彈出對話框”This is a nice pic!”:

var pic1 = document.getElementById("img1");
pic1.onmouseover = function() {
    alert("This is a nice pic!");
};

特別注意:如果以上代碼處于文檔的底部,在頁面剛剛加載時,我們將鼠標移動到img1上面。有可能由于代碼尚未執行,不會彈出我們設定的對話框!如今,這個延遲已經十分短暫。

事件處理程序中的this

通過DOM0級方法指定的事件處理程序,屬于元素方法。因此,我們在事件處理程序中的this引用的是該元素!通過以下例子來說明:

<input id="btn1" type="button" value="Click Me" />
...//省略
<script type="text/javascript">
  <!--
  var btn1 = document.getElementById("btn1");
  btn1.onclick = function() {
      alert(this.id + "\n" + this.type + "\n" + this.value);
  };
  -->
</script>

通過DOM0級方法刪除事件處理程序

要刪除事件處理程序,只需要將對應的事件處理程序屬性設置為null即可:

pic1.onmouseover = null;

三、DOM2級事件處理

1、addEventListener與removeEventListener

目前,幾乎所有的瀏覽器都支持DOM0事件模型,但鼓勵開發人員使用新的DOM2模型。DOM2模型與DOM0有兩個顯著區別:

  • 1、DOM2不依賴事件處理程序屬性

  • 2、可以同時對對象的同一事件注冊多個處理程序,它們按照注冊順序依次執行。

DOM2定義了2個方法:

addEventListener()  //指定事件處理程序
removeEventListener()  //刪除事件處理程序

所有DOM節點有包含這兩個方法,這兩個方法用法如下,它們都接收3個參數,第1個為要處理事件名(不含on),第2個事件處理函數,第3個布爾變量:

例如我們為按鈕btn1的單擊事件添加2個事件處理程序,事件處理程序在事件冒泡階段被處理:

<input id="btn1" type="button" value="Click Me" />
...
<script type="text/javascript">
  <!--
  var btn1 = document.getElementById("btn1");
  var handle1 = function() {
      alert("handle1!");
  }
  var handle2 = function() {
      alert("handle2!");
  }
  btn1.addEventListener("click", handle1, false);
  btn1.addEventListener("click", handle2, false);
  -->
</script>

當單擊btn1按鈕時,會依次彈出對話框:

handle1!
handle2!

我們可以用removeEventListener()方法來刪除我們剛才指定的事件處理程序,注意參數要保持一致:

btn1.removeEventListener("click", handle2, false);

此時單擊btn1按鈕,只會顯示handle1!。

要特別注意的是,如果我們使用匿名函數指定事件處理程序,便無法使用removeEventListener()方法刪除事件處理程序:

 btn1.addEventListener("click", function(){
     alert("click!");
 }, false);

 btn1.removeEventListener("click", function(){
     alert("click!");
 }, false);  //無法取消!

這樣是無法取消以上指定的事件處理程序的!因為上面addEventListener和removeEventListener中的2個事件處理函數雖然代碼相同,實質上是2個不同的函數引用。

另外,強調一點,以上兩個函數的第一個參數(要處理的事件名)是沒有on前綴的。這一點和IE不同,后面會說明。

tips: IE9, Firefox, Safari, Chrome以及Opera均支持DOM2級事件處理程序。

DOM2事件處理程序中的this

DOM2事件處理程序和DOM0相同,它們的this都在其依附的元素作用域中運行。this的指代參考DOM0的示例。這里之所以要特別指出DOM2的this,是為了和IE事件處理程序進行區分。IE中事件處理程序this與事件指定方式有關。

四、IE事件處理程序及跨瀏覽器支持

attachEvent()與detachEvent()

IE并沒有提供對W3C事件模型的支持,其實現了2個和DOM2模型類似的方法:

attachEvent()
detachEvent()

這兩個方法只接收2個參數:事件名稱以及事件處理函數。由于IE8及更早版本只支持事件冒泡,這兩個方法添加的事件處理程序會在事件冒泡階段被執行。

和DOM2不同的是:

  • 1、IE事件處理方法運行作用域為全局作用域,this指代window;

  • 2、第一個參數事件名以on為前綴;

  • 3、當為同一對象的相同事件指定多個處理程序時,執行順序和DOM2相反,IE中以添加它們的相反順序執行。

例如:

<input id="btn1" type="button" value="Click Me" />
...
<script type="text/javascript">
  <!--
  var btn1 = document.getElementById("btn1");
  var handle1 = function() {
      alert("handle1!" + "\n" + (this === window));
  };
  var handle2 = function() {
      alert("handle2!"+ "\n" + (this === window));
  };
  btn1.attachEvent("onclick", handle1);
  btn1.attachEvent("onclick", handle2);
  -->
</script>

執行結果:

handle2!
true

handle1!
true

跨瀏覽器支持

雖然可以使用屏蔽瀏覽器差異的JS庫,實際上,我們自己編寫一個跨瀏覽器兼容的事件處理代碼并不是一件困難的事情,同時更有利于我們對原生JavaScript的學習理解。我們使用一個習慣上稱為EventUtil的對象來進行跨瀏覽器事件處理:

var EventUtil = {
    addEventHandler : function(element, eventType,        handler) {
        if(element.addEventListener){
            element.addEventListener(eventType, handler, flase);
        } else if(element.attachEvent) {
            element.attachEvent("on" + eventType, handler);
        } else {
            element["on" + eventType] = handler;
        }
    },

    removeEventHandler : function(element, eventType, handler) {
        if(element.aremoveEventListener){
            element.addEventListener(eventType, handler, flase);
        } else if(element.detachEvent) {
            element.attachEvent("on" + eventType, handler);
        } else {
            element["on" + eventType] = null;
        }
    }
}

為了保證事件處理代碼能夠在大多數瀏覽器中一致地運行,我們這里只關注冒泡階段。以上代碼使用瀏覽器能力檢測,首先檢測是否支持DOM2級方法addEventListener和removeEventListener,如果支持則使用該方法;如果不支持該方法,檢測是否是IE8級更早版本的attachEvent或detachEvent方法,若支持則使用該方法;如果對以上2種方法都不支持,則使用DOM0級方法。要注意,DOM0級對每個事件只能指定一個事件處理程序。

以上對象使用示例如下:

var btn1 = document.getElementById("btn1");var handle1 = function() {
    alert("handle1!" + "\n" + (this === window));
};var handle2 = function() {
    alert("handle2!"+ "\n" + (this === window));
};
EventUtil.addEventHandler(btn1, "click", handler1);
EventUtil.addEventHandler(btn1, "click", handler2);

EventUtil.removeEventHandler(btn1, "click", handler2);

五、事件對象

在觸發某個事件時,會產生一個event對象。該對象中包含與事件有關的信息。例如觸發事件的元素、事件的類型、與特定事件相關的如鼠標位置信息等。

  • 1、DOM事件對象

  • 2、IE事件對象與跨瀏覽器事件對象

1、DOM事件對象

不論使用DOM0級還是DOM2級方法指定事件處理程序,事件觸發時都會自動將一個event對象傳入事件處理程序,例如:

var btn1 = document.getElementById("btn1");

btn1.onmouseover = function(evnt) {
    alert(evnt.type);
}var handle = function(evnt) {
    alert(evnt.type);
};
btn1.addEventListener("click", handle, false);

以上是一個簡單的event對象的示例。event對象中的type屬性是一個只讀字符串屬性,其中包含著事件的類型。例如我們上例中的click和onmouseover。event對象中包含有大量的有關事件的屬性和方法(例如event.stopPropagation()方法可用于停止事件在捕獲或者冒泡階段的繼續傳播,preventDefault()方法會取消阻止事件的行)在此就不一一列舉了。其中常用的如下:

屬性/方法值類型讀寫描述
currentTargetElementreadonly事件處理程序當前正在處理的元素
targetElementreadonly事件的目標
typeStringreadonly觸發事件的類型
preventDefaultFunctionreadonly取消事件默認行為,如鏈接的默認行為就是被單擊時跳轉到href指定的url
stopPropagationFunctionreadonly取消事件進一步冒泡或捕獲

2、IE事件對象與跨瀏覽器事件對象

IE事件對象

在IE中,當使用DOM0級指定事件處理程序時,event對象被認為是window的一個屬性,例如獲取鼠標點擊坐標的代碼:

var mouseLoc = function() {
    var loc = "x: " + window.event.screenX + "\n" +              "y: " + window.event.screenY;
    alert(loc);
};

當使用attachEvent()方法指定事件處理程序時,event對象會被作為參數傳入事件處理程序,我們將以上的代碼重寫:

var mouseLoc = function(event) {
    var loc = "x: " + event.screenX + "\n" +              "y: " + event.screenY;
    alert(loc);
};
btn1.attachEvent("onclick",  mouseLoc);

IE中event對象的相關屬性方法:

屬性/方法值類型讀寫描述
cancelBubbleBooleanread/write默認為false,置為true時取消事件冒泡(同DOM中stopPropagation)
returnValueBooleanread/write默認為true,設為false取消事件默認行為(同DOM中preventDefault)
srcElementElementreadonly事件目標
typeStringreadonly事件類型

跨瀏覽器事件對象

解決跨瀏覽器問題的思路是一貫的,我們可以對瀏覽器進行能力檢測,這里我們對上面的EventUtil對象進行擴展,對我們學習原生JS,這是一個很漂亮的對象:

var EventUtil = {
    addEventHandler : function(element, eventType, handler) {
        if(element.addEventListener){
            element.addEventListener(eventType, handler, flase);
        } else if(element.attachEvent) {
            element.attachEvent("on" + eventType, handler);
        } else {
            element["on" + eventType] = handler;
        }
    },

    removeEventHandler : function(element, eventType, handler) {
        if(element.aremoveEventListener){
            element.addEventListener(eventType, handler, flase);
        } else if(element.detachEvent) {
            element.attachEvent("on" + eventType, handler);
        } else {
            element["on" + eventType] = null;
        }
    },

    getEvent: function (event) {
        return event ? event : window.event;
    },

    getTarget: function (event) {
        return event.target || event.srcElement;
    },

    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },

    stopPropagation: function (event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubbles = true;
        }
    },

    getRelatedTarget: function (event) {
        if (event.relatedTarger) {            return event.relatedTarget;
        } else if (event.toElement) {            return event.toElement;
        } else if (event.fromElement) {            return event.fromElement;
        } else { return null; }
    }
}

看完了這篇文章,相信你對“JavaScript中如何實現事件冒泡與時間捕獲”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女