前言:
這篇文章起源於上次工作上的原因,在事件上出的
bug
,所以就抽空寫出一篇,也便於自己以後查閱,如若有幸被您閱讀的話,小妹備感榮幸,文章僅為個人理解,如果內容有誤的還望海涵,在您時間還方便的時候,希望能告知小妹!謝謝!
什麼是事件?
事件是文件和瀏覽器視窗中發生的特定的互動瞬間。 事件是
javascript
應用跳動的心臟,也是把所有東西黏在一起的膠水,當我們與瀏覽器中web
頁面進行某些型別的互動時,事件就發生了。
事件可能是使用者在某些內容上的點選,滑鼠經過某個特定元素或按下鍵盤上的某些按鍵,事件還可能是
web
瀏覽器中發生的事情,比如說某個web
頁面載入完成,或者是使用者滾動視窗或改變視窗大小。
什麼是事件流:
事件流描述的是從頁面中接受事件的順序,但有意思的是,微軟(
IE
)和網景(Netscape
)開發團隊居然提出了兩個截然相反的事件流概念,IE
的事件流是事件冒泡流(event bubbling),而Netscape的事件流是事件捕獲流(event capturing)。
事件冒泡
IE提出的事件流叫做事件冒泡,即事件開始時由最具體的元素接收,然後逐級向上傳播到較為不具體的節點,看一下以下示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body onclick="bodyClick()">
<div onclick="divClick()">
<button onclick="btn()">
<p onclick="p()">點選冒泡</p>
</button>
</div>
<script>
function p(){
console.log('p標籤被點選')
}
function btn(){
console.log("button被點選")
}
function divClick(event){
console.log('div被點選');
}
function bodyClick(){
console.log('body被點選')
}
</script>
</body>
</html>
複製程式碼
接下來我們點選一下頁面上的p元素,看看會發生什麼:
正如上面我們所說的,它會從一個最具體的的元素接收,然後逐級向上傳播,p=>button=>div=>body..........
事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會一直從水底冒出水面。
事件捕獲
網景公司提出的事件流叫事件捕獲流。
事件捕獲流的思想是不太具體的
DOM
節點應該更早接收到事件,而最具體的節點應該最後接收到事件,針對上面同樣的例子,點選按鈕,那麼此時click
事件會按照這樣傳播:(下面我們就借用addEventListener
的第三個引數來模擬事件捕獲流)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<button>
<p>點選捕獲</p>
</button>
</div>
<script>
let oP=document.querySelector('p');
let oB=document.querySelector('button');
let oD=document.querySelector('div');
let oBody=document.querySelector('body');
oP.addEventListener('click',function(){
console.log('p標籤被點選')
},true);
oB.addEventListener('click',function(){
console.log("button被點選")
},true);
oD.addEventListener('click', function(){
console.log('div被點選')
},true);
oBody.addEventListener('click',function(){
console.log('body被點選')
},true);
</script>
</body>
</html>
複製程式碼
同樣我們看一下後臺的列印結果:
正如我們看到的,和冒泡流萬全相反,從最不具體的元素接收到最具體的元素接收事件 body=>div=>button=>p
DOM
0級事件處理程式:
DOM 0級
事件規定的事件流包含3個階段,事件捕獲階段、處於目標階段、事件冒泡階段。首先發生的事件捕獲為截獲事件提供機會,然後是實際的目標接收事件,最後一個階段是事件冒泡階段,可以在這個階段對事件做出響應。
在
DOM
事件流中,事件的目標在捕獲階段不會接收到事件,這意味著在捕獲階段事件從document
到<p>
就停止了,下個階段是處於目標階段,於是事件在<p>
上發生,並在事件處理中被看成冒泡階段的一部分,然後,冒泡階段發生,事件又傳播回document。
下面是我們模擬它的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">DOM事件流</button>
<script>
let btn=document.getElementById("btn");
btn.onclick=function(event){
console.log("div 處於目標階段");
};
document.body.addEventListener("click",function(event){
console.log("event bubble 事件冒泡");
},false);
document.body.addEventListener("click",function(event){
console.log("event catch 事件捕獲");
},true);
</script>
</body>
</html>
複製程式碼
看看後臺給出什麼結果:
整體流程如下:就是這樣一個流程,先捕獲,然後處理,然後再冒泡出去。
關於DOM 2級事件處理程式:
DOM 2級事件定義了兩方法:用於處理新增事件和刪除事件的操作:新增事件 addEventListener()
刪除事件 removeEventListener()
所有DOM
節點中都包含這兩個方法,並且他們都包含3個引數:
使用DOM
2級事件處理程式的主要好處是可以新增多個事件處理程式,事件處理會按照他們的順序觸發,通過addEventListener
新增的事件只能用removeEventListener
來移除,移除時傳入的引數與新增時使用的引數必須相同,這也意味著新增的匿名函式將無法移除,(注意:我們預設的第三個引數都是預設false
,是指在冒泡階段新增,大多數情況下,都是將事件處理程式新增到事件的冒泡階段,這樣可以最大限度的相容各個瀏覽器)
//這是一個DOM 2級事件 新增一個簡單的事件(此時新增的是一個匿名函式)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按鈕</button>
<script>
let btn=document.querySelector('button');
btn.addEventListener('click',function(){
console.log('我是按鈕')
},false) //當第三個引數不寫時,也是預設為false(冒泡時新增事件)
</script>
</body>
</html>
複製程式碼
那麼我們試試命名函式的寫法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按鈕</button>
<script>
let btn=document.querySelector('button');
btn.addEventListener('click',foo,false);
function foo(){
console.log('我是按鈕')
}
//其實操作就是把寫在裡面的函式拿到了外面,而在原來的位置用函式名來代替
</script>
</body>
</html>
複製程式碼
那麼我們新增兩個事件怎麼寫呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按鈕</button>
<script>
let btn=document.querySelector('button');
//第一個事件
btn.addEventListener('click',foo,false);
function foo(){
console.log('我是按鈕')
}
//第二個事件
btn.addEventListener('click',newFoo,false);
function newFoo(){
console.log('我是新按鈕')
}
</script>
</body>
</html>
複製程式碼
那麼我們看看這兩個事件的執行順序是怎樣的:
所以說,我們可以使用addEventListener
新增多個事件,事件的順序就是按照我們程式寫的順序執行的。
那我們試試DOM
0級事件處理程式,是如何處理新增兩個事件後的執行的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="foo()" onclick="newFoo()">按鈕</button>
<script>
function foo(){
console.log(2)
}
function newFoo(){
console.log(9)
}
</script>
</body>
</html>
複製程式碼
看一下結果:
結果只執行了第一個事件,第二個被忽略,所以當我們只新增一個事件時,可以使用DOM
0級事件處理程式來執行,而當我們的需求是多個事件時,我們就需要用到addEventLiener
去執行。
未完待續:
以上就是事件冒泡,事件捕獲,DOM
事件流,DOM 2
級事件流的內容,但是還有沒有敘述完整,本人會在這1-2天內繼續補充,敬請期待!謝謝閱讀!
接下來我還會持續追加,看文章的小夥伴們可以新增一下關注哦!
作者:晴天de雨滴
出處:https://juejin.im/post/5a2521bef265da432e5bd8e1
版權所有,歡迎保留原文連結進行轉載:)
複製程式碼
如果你對我對文章感興趣或者有些建議想說給我聽?,也可以新增一下微信哦!
如果親感覺我的文章還不錯的話,可以一下新增關注哦!-----再或者感覺我的文章對您有所幫助,可以掃描二維碼打賞一下我呦!這樣我會更有動力給大家提供更優質的文章哦! 謝謝您!!!
最後:
祝各位工作順利!
-小菜鳥Christine
複製程式碼