1. 程式人生 > 實用技巧 >DOM事件模型

DOM事件模型

事件

參考:

W3C連結

瞭解DOM 事件模型

DOM 事件詳解

事件捕獲、事件冒泡以及事件代理

原生JavaScript和Vue、小程式都是如何阻止事件冒泡的?


DOM事件級別


1 事件流

事件流描述的是從頁面中接受事件的順序。

1.1 事件冒泡

IE 的事件流叫事件冒泡,即事件開始時由最具體的元素接受,然後逐級向上傳播到較為不具體的節點(文件),Chrome,Firefox和Safari會將事件一直冒泡到 window 物件。

1.2 事件捕獲

Netscape Communicator 團隊提出的另一種事件流叫做事件捕獲。事件捕獲的思想是不太具體的節點應該更早接受到事件,而最具體的節點應該最後接收到事件。事件捕獲的用以在於事件到達預定目標之前捕獲它。一般從document物件開始傳播,用的較少。

1.3 DOM事件流

上圖是W3C標準的DOM事件流模型圖。

“DOM2級事件” 規定的事件流包括三個階段:事件捕獲階段、處於目標階段、事件冒泡階段。


2 事件處理程式

前面說的是事件,事件就是使用者或瀏覽器自身執行的某種動作。如:click是事件的名字,事件處理程式就是onclick。為事件指定處理程式的方式有好幾種

2.1 HTML 事件處理程式

其實就是,HTML 的on屬性

<button onclick="doxxx()">點選</button>

使用這個方法指定的監聽程式碼只會在冒泡階段觸發。

2.2 DOM0 級事件處理程式,缺點:無法設定多個事件處理函式

元素節點的事件屬性。

let btn = document.getElementById("myBtn:);
btn.onclick = function () {
    alert("Clickes")      
}

如果想刪除只需:btn.onclick = null;  // 刪除事件處理程式

2.3 DOM2 級事件處理程式,可以為事件設定多個事件處理函式,可以通過第三個引數 ( useCapture ) 設定在什麼階段執行事件處理函式,預設是 false, 即在事件冒泡階段執行事件處理函式。

DOM2級事件定義了兩個方法,用於處理指定 和 刪除事件處理程式的操作:addEventListener()

removeEventListener()

所有DOM節點中都包含這兩種方法。並且都接受三個引數:要處理的事件名作為事件處理程式的函式一個布林值(預設false表冒泡)

(1)EventTarget.addEventListener()

function print() {
  console.log('Print Hello world');
}

var btn = document.getElementById('btn');
btn.addEventListener('click', print, false);

上面程式碼的意思就是,節點id為btn的元素,使用addEventListener方法繫結click事件,點選的時候會監聽函式print會發生。另外,因為useCapture設定為false,所以該函式只在冒泡階段觸發
當我們需要新增多個不同的監聽函式,使用addEventListener非常棒,遵從先新增先觸發原則,而且不小心在同一個事件重複添加了同一個函式,它還會自動移除,該函式只會執行一次。

(2)EventTarget.removeEventListener()
顧名思義,用來移除addEventListener方法新增的事件監聽函式。
它的引數和addEventListener方法一致,而且寫的時候要一一對應。要做到三同,一是在同一個元素節點,二是同一個監聽函式,三是第三個引數要一致。

2.4 IE 事件處理程式

(1)事件繫結監聽函式:attachEvent(eventType, listener)
(2)事件移除監聽函式:detachEvent(eventType, listener)


3 事件物件

3.1 DOM 中的事件物件

事件發生的時候,會將一個 event 物件傳入到事件處理程式中,從而可以使用物件的屬性和方法。我隨意列出幾個。
bubbles:返回一個布林值,表示當前事件是否會冒泡。該屬性為只讀屬性
cancelable:返回一個布林值,表示事件是否可以取消。該屬性為只讀屬性
currentTarget:事件處理程式當前正在處理事件的那個元素
preventDefault():取消事件的預設行為。如果 cancelable 是true,則可以使用這個方法
stopPropagation():取消事件的進一步捕獲或冒泡。如果 bubbles為 true,則可以使用這個方法。
事件處理程式使用DOM0 級或是 DOM2 級,都會傳入 event 物件,這個我們不用care。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
      console.log(event.type);    //"click"
  };
btn.addEventListener("click", function(event){
      console.log(event.type);    //"click"
  }, false);
<button onclick="console.log(event.type)()">點選</button>

3.2 IE中的事件物件

與訪問DOM中的event物件不同,要訪問IE中的event物件有幾種不同的方式,取決於指定事件處理程式的方法。

(1) HTML 事件處理程式

<button onclick="console.log(event.type)()">點選</button>

(2) DOM0 級事件處理程式

let btn = document.getElementById("btn");
btn.onclick = function(){
 var event = window.event;
 console.log(event.type);     //"click"
};

(3) DOM2 級事件處理程式

let btn = document.getElementById("btn");
btn.attachEvent("onclick", function(event){
 console.log(event.type);         //"click"
});

4 事件型別(DMO3 級事件規定了以下幾類事件)

DOM3 級事件是在 DOM2 級事件的基礎上添加了更多的事件型別,允許自定義事件。

  • UI事件,當用戶與頁面上的元素互動時觸發,如:load、scroll
  • 焦點事件,當元素獲得或失去焦點時觸發,如:blur、focus
  • 滑鼠事件,當用戶通過滑鼠在頁面執行操作時觸發如:dbclick、mouseup
  • 滾輪事件,當使用滑鼠滾輪或類似裝置時觸發,如:mousewheel
  • 文字事件,當在文件中輸入文字時觸發,如:textInput
  • 鍵盤事件,當用戶通過鍵盤在頁面上執行操作時觸發,如:keydown、keypress
  • 合成事件,當為IME(輸入法編輯器)輸入字元時觸發,如:compositionstart
  • 變動事件,當底層DOM結構發生變化時觸發,如:DOMsubtreeModified

如何阻止冒泡

例子:

<div onclick="alert('最外層')">
    <div onclick="alert('中間層')">
        <a id="ahref" href="http://www.javanx.cn" onclick="alert('最裡層')">點選我</a>
    </div>
</div>

點選:點選我 --》最裡層 --》中間層 --》最外層 --》然後轉跳連結。這就是冒泡。

1.JavaScript 中

event.stopPropagation()  // propagation: 傳播
$(function() {
    $("#ahref").click(function(event) {
        event.stopPropagation();
    });
});

點選:點選我 --》 最裡層 --》轉跳連結  事件處理過程中,阻止了事件冒泡,但不會阻擊預設行為(執行了超連結的跳轉)

return false

$(function() {
    $("#ahref").click(function(event) {
        return false;
    });
});

點選:點選我 --》 最裡層 --》但不會轉跳連結事件處理過程中,阻止了事件冒泡,也阻止了預設行為(沒有執行超連結的跳轉)

event.preventDefault()

$(function() {
    $("#ahref").click(function(event) {
        event.preventDefault()  
    });
});

點選:最裡層 --》中間層 --》最外層,但最後沒有轉跳  不能阻止事件冒泡,但阻止了預設行為。

2.Vue 解決事件冒泡

Vue.js 提供了事件修飾符,我們只需要新增 click.stop 即可預防事件冒泡

<div @click="cancelSelect">
    <div class="picker_alert" @click.stop>
        <div class="ofh">
            <span @click="toRoomManagement">編輯</span>
            <span @click="confirmRoom">確定</span>
        </div>
    </div>
</div>

Vue修飾符:.stop, .prevent, .capture, .self, .once

<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
 
<!-- 提交事件不再過載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
 
<!-- 修飾符可以串聯 -->
<a v-on:click.stop.prevent="doThat"></a>
 
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
 
<!-- 新增事件偵聽器時使用事件捕獲模式 -->
<div v-on:click.capture="doThis">...</div>
 
<!-- 只當事件在該元素本身(比如不是子元素)觸發時觸發回撥 -->
<div v-on:click.self="doThat">...</div>

提示:使用修飾符時,順序很重要;相應的程式碼會以同樣的順序產生。
因此,用 @click.prevent.self 會阻止所有的點選,而 @click.self.prevent 只會阻止元素上的點選。