首頁  >  文章  >  web前端  >  JavaScript事件之事件冒泡與時間捕獲(總結分享)

JavaScript事件之事件冒泡與時間捕獲(總結分享)

WBOY
WBOY轉載
2021-12-23 18:49:382398瀏覽

這篇文章為大家帶來了JavaScript中關於事件的基礎知識詳解,其中包括了事件冒泡和時間捕獲,希望對大家有幫助。

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引用的是該元素!透過以下範例來說明:

6c62a7e2513a7465a5a873220f3f5dac
...//省略
8019067d09615e43c7904885b5246f0a
  89e3bb261a36e34e3f1c9a90f67afd83
2cacc6d41bbb37262a98f745aa00fbf0

透過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個事件處理程序,事件處理程序在事件冒泡階段被處理:

6c62a7e2513a7465a5a873220f3f5dac
...
8019067d09615e43c7904885b5246f0a
  0e82aacda029e768165406ce66a9f59e
2cacc6d41bbb37262a98f745aa00fbf0

當點擊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中以添加它们的相反顺序执行。

例如:

6c62a7e2513a7465a5a873220f3f5dac
...
8019067d09615e43c7904885b5246f0a
  84f07fc1f7167f067b3f15a898dda831
2cacc6d41bbb37262a98f745aa00fbf0

执行结果:

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()方法会取消阻止事件的行)在此就不一一列举了。其中常用的如下:

属性/方法 值类型 读写 描述
currentTarget Element readonly 事件处理程序当前正在处理的元素
target Element readonly 事件的目标
type String readonly 触发事件的类型
preventDefault Function readonly 取消事件默认行为,如链接的默认行为就是被单击时跳转到href指定的url
stopPropagation Function readonly 取消事件进一步冒泡或捕获

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对象的相关属性方法:

属性/方法 值类型 读写 描述
cancelBubble Boolean read/write 默认为false,置为true时取消事件冒泡(同DOM中stopPropagation)
returnValue Boolean read/write 默认为true,设为false取消事件默认行为(同DOM中preventDefault)
srcElement Element readonly 事件目标
type String readonly 事件类型

跨浏览器事件对象

解决跨浏览器问题的思路是一贯的,我们可以对浏览器进行能力检测,这里我们对上面的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学习教程

以上是JavaScript事件之事件冒泡與時間捕獲(總結分享)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除