JavaScript DOM

DOM 事件模型

DOM(Document Object Model 文件對象模型)

DOM將用例如XML、HTML等標記語言寫成的結構化文檔當作一顆樹,該樹上的節點也便是文檔內的節點。簡單來講,DOM是一組API,可使用戶經過任何實現了DOM API的語言操縱任何知足DOM標準的文檔。javascript

DOM 0級事件模式

<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Hello World</title> </head> <body> <div class='test'>Test</div> <script> let div = document.getElementsByClassName('test')[0]; div.onclick = function(){ console.log('click'); } </script> </body> </html> 

 

 


<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Hello World</title> </head> <body> <div class='test' onclick='console.log("click)'>Test</div> </body> </html> 

 

上述代碼都爲類名爲test的div綁定了一個click事件發生時觸發的方法。這種爲DOM元素設置事件函數的方法即是DOM 0級事件模型中規定的。除此以外,DOM 0級事件模型還不容許爲一個元素的同一事件綁定多個處理方法。若綁定了多個,則最後一個函數覆蓋以前的。html

<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Hello World</title> </head> <body> <div class='test'>Test</div> <script> let div = document.getElementsByClassName('test')[0]; div.onclick = function(){ console.log('click'); } //若是用戶點擊Test則會在控制檯輸出click again而不是click。 div.onclick = function(){ console.log('click again'); } </script> </body> </html> 

 

 

DOM 2級事件模型

DOM 2級事件模型爲咱們提供兩個方法分別用來添加和移除事件處理方法。前端

  • addEventListener()
  • removeEventListener()

這兩個方法的前兩個參數是相同的,分別是事件名和事件處理函數(remove方法沒法移除匿名函數)。而add方法則多出了一個參數,若傳入true,則事件處理方法在事件捕獲階段被調用,反之則在事件冒泡階段被調用。java


<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Hello World</title> </head> <body> <div class='test'>Test</div> <script> let div = document.getElementsByClassName('test')[0]; div.addEventListener('click', function(){ console.log('click'); }, false); div.addEventListener('click', function(){ console.log('click again'); }, true); </script> </body> </html> 

 

 

與DOM 0級不一樣,DOM 2級事件模型容許你爲同個元素的同個事件添加多個事件處理函數,在觸發時間時將會按照文檔順序被前後調用。瀏覽器

事件的冒泡與捕獲

image

<!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>Hello World</title> </head> <body> <div id='one'> <div id='two'> <div id='three'> <p>Test</p> </div> </div> </div> <script> let div1 = document.getElementById('one'); let div2 = document.getElementById('two'); let div3 = document.getElementById('three'); div1.addEventListenr('click' , function(event){ console.log('one'); }, false); div2.addEventListenr('click' , function(event){ console.log('two'); }, false); div3.addEventListenr('click' , function(event){ console.log('three'); }, false); div1.addEventListenr('click' , function(event){ console.log('one'); }, true); div2.addEventListenr('click' , function(event){ console.log('two'); }, true); div3.addEventListenr('click' , function(event){ console.log('three'); }, true); </script> </body> </html>





 

DOM 事件流

說實話,如今不管是什麼框架你都離不開操做DOM啊,畢竟這是你展現的最基本元素,就像人的細胞。想起了dom事件流原理,好多人不明白,只知道click mouseout等實用場景,真要理解和更進一步的前端是要必須:理論+實踐 並行的。

固然,DOM事件所囊括的知識較爲龐雜,因此本文專一與本身學習時所碰到的難點,DOM事件流。markdown

流的概念,在現今的JavaScript中隨處可見。好比說React中的單向數據流,Node中的流,又或是今天本文所講的DOM事件流。都是流的一種生動體現。至於流的具體概念,咱們採用下文的解釋:網絡

用術語說流是對輸入輸出設備的抽象。以程序的角度說,流是具備方向的數據。框架

事件流之事件冒泡與事件捕獲dom

在瀏覽器發展的過程當中,開發團隊遇到了一個問題。那就是頁面中的哪一部分擁有特定的事件?函數

能夠想象畫在一張紙上的一組同心圓,若是你把手指放在圓心上,那麼你的手指指向的其實不是一個圓,而是紙上全部的圓。放到實際頁面中就是,你點擊一個按鈕,事實上你還同時點擊了按鈕全部的父元素。

開發團隊的問題就在於,當點擊按鈕時,是按鈕最外層的父元素先收到事件並執行,仍是具體元素先收到事件並執行?因此這兒引入了事件流的概念。

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

由於有兩種觀點,因此事件流也有兩種,分別是事件冒泡和事件捕獲。現行的主流是事件冒泡。

事件冒泡即事件開始時,由最具體的元素接收(也就是事件發生所在的節點),而後逐級傳播到較爲不具體的節點。

舉個栗子,就很容易明白了。

而後,咱們給 button 和它的父元素,加入點擊事件。

效果如圖所示:

在代碼所示的頁面中,若是點擊了button,那麼這個點擊事件會按以下的順序傳播(Chrome瀏覽器):

1. button

2. body

3. document

4. window

也就是說,click事件首先在 <button> 元素上發生,而後逐級向上傳播。這就是事件冒泡。

事件捕獲的概念,與事件冒泡正好相反。它認爲當某個事件發生時,父元素應該更早接收到事件,具體元素則最後接收到事件。好比說剛纔的demo,若是是事件捕獲的話,事件發生順序會是這樣的:

1. window

2. document

3. body

4. button

固然,因爲時代更迭,事件冒泡方式更勝一籌。因此放心的使用事件冒泡,有特殊須要再使用事件捕獲便可。

DOM事件流

DOM事件流包括三個階段:

1. 事件捕獲階段

2. 處於目標階段

3. 事件冒泡階段

如圖所示(圖片源於網絡,若侵權請告知):

事件捕獲階段

也就是說,當事件發生時,首先發生的是事件捕獲,爲父元素截獲事件提供了機會。

例如,我把上面的Demo中,window點擊事件更改成使用事件捕獲模式。(addEventListener最後一個參數, 爲true則表明使用事件捕獲模式 ,false則表示使用事件冒泡模式。不理解的能夠去學習一下addEventListener函數的使用)


此時,點擊button的效果是這樣的。

能夠看到,點擊事件先被父元素截獲了,且該函數只在事件捕獲階段起做用。

處於目標與事件冒泡階段

事件到了具體元素時,在具體元素上發生,而且被當作冒泡階段的一部分。隨後,冒泡階段發生,事件開始冒泡。

阻止事件冒泡

事件冒泡過程,是能夠被阻止的。防止事件冒泡而帶來沒必要要的錯誤和困擾。

這個方法就是: stopPropagation() 

咱們對 button 的click事件作一些改造。


點擊後,效果以下圖:

不難看出,事件在到達具體元素後,中止了冒泡。但不影響父元素的事件捕獲。

小結

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

分有事件冒泡與事件捕獲兩種。

DOM事件流的三個階段:

1. 事件捕獲階段

2. 處於目標階段

3. 事件冒泡階段

相關文章
相關標籤/搜索