DOM 事件模型包括捕獲和冒泡,捕獲是從上往下到達目標元素,冒泡是從當前元素,也就是目標元素往上到 windowhtml
流的概念,在現今的 JavaScript 中隨處可見。好比說 React 中的單向數據流,Node 中的流,還有 DOM 事件流,都是流的一種生動體現。
至於流的具體概念,用術語說流是對輸入輸出設備的抽象。以程序的角度說,流是具備方向的數據。瀏覽器
瀏覽器在爲當前頁面與用戶作交互的過程當中,好比點擊鼠標左鍵,會出現這個左鍵是怎麼傳到頁面上,還有怎麼響應的問題。函數
事件流所描述的就是從頁面中接受事件的順序,事件流分爲兩種:事件冒泡(主流)和事件捕獲spa
事件開始時由具體元素接收,而後逐級向上傳播到父元素code
舉個例子:htm
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Event Bubbling</title> </head> <body> <button id="clickMe">Click Me</button> </body> </html>
咱們給 button 和它的父元素,加入點擊事件對象
var button = document.getElementById('clickMe'); button.onclick = function() { console.log('1. You click Button'); }; document.body.onclick = function() { console.log('2. You click body'); }; document.onclick = function() { console.log('3. You click document'); }; window.onclick = function() { console.log('4. You click window'); };
點擊按鈕運行效果:blog
也就是說,click 事件首先在 <button> 元素上發生,而後逐級向上傳播,這就是事件冒泡seo
父元素的節點更早接收事件,而具體元素最後接收事件,與事件冒泡相反事件
DOM事件流包括三個階段:
事件捕獲階段
處於目標階段
事件冒泡階段
當事件發生時,首先發生的是事件捕獲,爲父元素截獲事件提供了機會
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Event Bubbling</title> </head> <body> <button id="clickMe">Click Me</button> </body> </html>
上面事件冒泡的 Demo 中,window 點擊事件更改成使用事件捕獲模式
var button = document.getElementById('clickMe'); button.onclick = function() { console.log('1. You click Button'); }; document.body.onclick = function() { console.log('2. You click body'); }; document.onclick = function() { console.log('3. You click document'); }; // window.onclick = function() { // console.log('4. You click window'); // }; window.addEventListener('click', function() { console.log('4. You click window'); }, true);
此時,點擊 button 的效果是這樣的:
能夠看到,點擊事件先被父元素截獲了,且該函數只在事件捕獲階段起做用
事件到了具體元素時,在具體元素上發生,而且被當作冒泡階段的一部分
最後,冒泡階段發生,事件開始冒泡
事件冒泡過程,是能夠被阻止的。防止事件冒泡而帶來沒必要要的錯誤和困擾。
阻止方法是使用 stopPropagation(),舉個例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Event Bubbling</title> </head> <body> <button id="clickMe">Click Me</button> </body> </html>
仍是上面的 demo,這裏對 button 的 click 事件作了一些改造:
var button = document.getElementById('clickMe'); // button.onclick = function() { // console.log('1. You click Button'); // }; button.addEventListener('click', function(event) { // 這裏event爲事件對象 console.log('1. You click Button'); event.stopPropagation(); console.log('Stop Propagation!'); }, false); document.body.onclick = function() { console.log('2. You click body'); }; document.onclick = function() { console.log('3. You click document'); }; window.addEventListener('click', function() { console.log('4. You click window'); }, true);
點擊後,效果以下圖:
不難看出,事件在到達具體元素後,中止了冒泡,但不影響父元素的事件捕獲
DOM0級事件,就是直接經過 onclick 等方式實現相應的事件
<input id="myButton" type="button" value="Click Me" onclick="alert('Hello1');" >
document.getElementById("myButton").onclick = function () { alert('Hello2'); }
運行結果 - 點擊彈出:
這說明 DOM0 級添加事件時,後面的事件會覆蓋前面的事件,而 DOM2級則不會,多個事件都會執行;
另外,DOM0級事件具備很好的跨瀏覽器優點,會以最快的速度綁定,但因爲綁定速度太快,可能頁面還未徹底加載出來,以致於事件可能沒法正常運行
主流瀏覽器 DOM2 級事件是經過如下兩個方法用於處理指定和刪除事件處理程序的操做:
全部的 DOM 節點都包含這兩個方法,使用方法以下:
而且它們都接受三個參數:
舉個例子:
<input id="myButton" type="button" value="Click Me" onclick="alert('Hello1');" >
document.getElementById("myButton").onclick = function () { alert('Hello2'); } document.getElementById('myButton').addEventListener('click', function() { alert('Hello3'); }, true) document.getElementById('myButton').addEventListener('click', function() { alert('Hello4'); }, true) document.getElementById('myButton').addEventListener('click', function() { alert('Hello5'); }, false)
運行結果:
注意:只有 DOM2級事件包含如下三個階段
事件捕獲階段
處於目標階段
事件冒泡階段