Dom 事件詳解

事件是 JavaScript 與 HTML 交互的基礎。要實現用戶與頁面的交互,先要對目標元素綁定特定的事件、設置事件處理函數,而後用戶觸發事件,事件處理函數執行,產生交互效果。
<!-- more -->

DOM 事件級別

DOM 級別分爲四個級別:DOM0 級、DOM1 級、DOM2 級、DOM3 級;
DOM級別
<br/>
DOM 事件級別分爲三個級別:javascript

  1. DOM0 級事件
<button id="btn" type="button"></button>
<script>
    var btn = document.getElementById('btn')
    btn.onclick = function() {
        console.log('Hello World')
    }
    // btn.onclick = null // 解綁事件
</script>
缺點:沒法設置多個事件處理函數
  1. DOM2 級事件
<button id="btn" type="button"></button>
<script>
    var btn = document.getElementById('btn');    
    btn.addEventListener('click', showFn, false)
    btn.addEventListener('click', showFn2, false)
    // btn.removeEventListener('click', showFn, false) // 解綁事件 
    function showFn() {
        alert('Hello World');
    }
     function showFn2() {
        alert('Hello World2');
    } 
</script>
能夠爲事件設置多個事件處理函數,能夠經過第三個參數 ( useCapture ) 設置在什麼階段執行事件處理函數,默認是 false, 即在事件冒泡階段執行事件處理函數。

須要注意的是在 IE8 及如下版本須要用 attachEventdetachEvent 實現,只有兩個參數,事件名須要以 on 開頭,只支持在事件冒泡階段執行事件處理函數。html

  1. DOM3 級事件
DOM3 級事件是在 DOM2 級事件的基礎上添加了更多的事件類型,容許自定義事件。
  • UI事件,當用戶與頁面上的元素交互時觸發,如:load、scroll
  • 焦點事件,當元素得到或失去焦點時觸發,如:blur、focus
  • 鼠標事件,當用戶經過鼠標在頁面執行操做時觸發如:dbclick、mouseup
  • 滾輪事件,當使用鼠標滾輪或相似設備時觸發,如:mousewheel
  • 文本事件,當在文檔中輸入文本時觸發,如:textInput
  • 鍵盤事件,當用戶經過鍵盤在頁面上執行操做時觸發,如:keydown、keypress
  • 合成事件,當爲IME(輸入法編輯器)輸入字符時觸發,如:compositionstart
  • 變更事件,當底層DOM結構發生變化時觸發,如:DOMsubtreeModified
// 自定義事件
var event = new Event('test')
// 給元素綁定事件
domElement.addEventListener('test', function() {
    console.log('event test')
},)

// 觸發事件
setTimeout(function() {
    domElement.dispatchEvent(event)
}, 1000)

DOM 事件流

想象畫在一張紙上的一組同心圓。若是把手指放在圓心上,那麼手指指向的不單單是一個圓,而是紙上的全部圓。因此若是點擊了某個按鈕,點擊事件不單單發生在這個按鈕上,整個頁面也被點擊了。

事件流又稱爲事件傳播,描述的是從頁面中接收事件的順序。DOM2 級事件規定事件流包括三個階段: 事件捕獲(capturing phase)目標事件(target phase)事件冒泡(bubbling phase)
<br/>
發生的順序是:事件捕獲階段 --> 目標事件階段 --> 事件冒泡階段 java

事件流

事件冒泡

事件開始時由最具體的元素(目標元素)接收,而後逐級向上傳播。
<style>
  #parent {
      width: 200px;
      height: 200px;
      background-color: green;
  }
  #child {
      width: 100px;
      height: 100px;
      background-color: yellow;
  }
</style>

<div id="parent">
  <div id="child">目標元素</div>
  父級元素
</div>

<script>
  var parent = document.getElementById('parent')
  var child = document.getElementById('child')
  
  parent.addEventListener('click', function(e) {
      console.log('parent bubbling')
  }, false)
  
  child.addEventListener('click', function() {
      console.log('target bubbling')
  }, false)
  
  document.body.addEventListener('click', function() {
      console.log('body bubbling')
  }, false)
  
  document.documentElement.addEventListener('click', function() {
      console.log('html bubbling')
  }, false)
  
  document.addEventListener('click', function() {
      console.log('document bubbling')
  }, false)
  
  window.addEventListener('click', function() {
      console.log('window bubbling')
  }, false)
</script>

運行結果:
<br/>
bubblingsegmentfault

事件捕獲

事件按 window -> document -> html -> body -> ... -> 目標元素 的方向向下層元素傳遞。
<style>
  #parent {
      width: 200px;
      height: 200px;
      background-color: green;
  }
  #child {
      width: 100px;
      height: 100px;
      background-color: yellow;
  }
</style>

<div id="parent">
  <div id="child">目標元素</div>
  父級元素
</div>

<script>
  var parent = document.getElementById('parent')
  var child = document.getElementById('child')
  
  parent.addEventListener('click', function(e) {
      console.log('parent capture')
  }, true)
  
  child.addEventListener('click', function() {
      console.log('target capture')
  }, true)
  
  document.body.addEventListener('click', function() {
      console.log('body capture')
  }, true)
  
  document.documentElement.addEventListener('click', function() {
      console.log('html capture')
  }, true)
  
  document.addEventListener('click', function() {
      console.log('document capture')
  }, true)
  
  window.addEventListener('click', function() {
      console.log('window capture')
  }, true)
</script>

運行結果:
<br/>
![bubbling](https://user-gold-cdn.xitu.io...
)瀏覽器

事件對象參數 event

在用戶觸發事件,執行事件處理函數的時候,默認會向事件處理函數傳入一個 event 對象,它記錄了該事件的狀態和行爲。

event 經常使用屬性和方法

  • type 事件類型
  • target 事件發出者(觸發事件的元素)
  • currentTarget

事件監聽者(被綁定事件的元素)dom

  • stopPropagation() 阻止事件冒泡或捕獲
  • preventDefault() 阻止瀏覽器默認行爲

target 、currentTarget 與 this

<div id="parent">
    <div id="child"></div>
</div>
<script>
    var parent = document.getElementById('parent')
    
    function handler(e) {
        console.log(e.target)
        console.log(e.currentTarget)
        console.log(this)
    }
    // 給父盒子註冊點擊事件
    parent.addEventListener('click', handler, false)
</script>

當點擊 parent 時,輸出:編輯器

1 <div id="parent">...</div>
2 <div id="parent">...</div>
3 <div id="parent">...</div>

當點擊 child 時,輸出:函數

1 <div id="child">...</div>
2 <div id="parent">...</div>
3 <div id="parent">...</div>
因此 target 是事件發出者, curentTarget 是事件監聽者,事件處理函數中的 this 等同於 e.currentTarget

event 對象的一些兼容性寫法

  • 得到 event
// 事件處理函數
function handleClick(event) {
    var e = event || window.event
    ···
}
  • 得到 target
···
var target = e.target || e.srcElement
···
  • 阻止瀏覽器默認行爲
···
e.preventDefault ? e.preventDefault() : (e.returnValue = false)
···
  • 阻止冒泡
···
e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true)
···
  • 事件綁定與解綁
function addEvent(element, type, fn) {
    element.addEventListener ? element.addEventListener(type, fn, false) : element.attachEvent('on'+ type, fn)
}

function removeEvent(element, type, fn) {
    element.removeEventListener ? element.removeEventListener(type, fn, false) : element.detachEvent('on'+ type, fn)
}

屬性表

  • 基礎屬性
屬性 描述
altKey 返回當事件被觸發時,」ALT」 是否被按下。
button 返回當事件被觸發時,哪一個鼠標按鈕被點擊。
clientX 返回當事件被觸發時,鼠標指針的水平座標。
clientY 返回當事件被觸發時,鼠標指針的垂直座標。
ctrlKey 返回當事件被觸發時,」CTRL」 鍵是否被按下。
metaKey 返回當事件被觸發時,」meta」 鍵是否被按下。
relatedTarget 返回與事件的目標節點相關的節點。
screenX 返回當某個事件被觸發時,鼠標指針的水平座標。
screenY 返回當某個事件被觸發時,鼠標指針的垂直座標。
shiftKey 返回當事件被觸發時,」SHIFT」 鍵是否被按下。
  • IE 屬性
屬性 描述
cancelBubble 若是事件句柄想阻止事件傳播到包容對象,必須把該屬性設爲 true。
fromElement 對於 mouseover 和 mouseout 事件,fromElement 引用移出鼠標的元素。
keyCode 對於 keypress 事件,該屬性聲明瞭被敲擊的鍵生成的 Unicode 字符碼。對於 keydown 和 keyup
offsetX,offsetY 發生事件的地點在事件源元素的座標系統中的 x 座標和 y 座標。
returnValue 若是設置了該屬性,它的值比事件句柄的返回值優先級高。把這個屬性設置爲 false 能夠阻止瀏覽器默認行爲
srcElement 對於生成事件的 Window 對象、Document 對象或 Element 對象的引用。
toElement 對於 mouseover 和 mouseout 事件,該屬性引用移入鼠標的元素。
x,y 事件發生的位置的 x 座標和 y 座標,它們相對於用CSS動態定位的最內層包容元素。
  • 標準 event 屬性(2級 DOM 事件標準定義的屬性)
屬性或方法 描述
bubbles 返回布爾值,指示事件是不是冒泡事件類型。
cancelable 返回布爾值,指示事件是否可擁可取消的默認動做。
currentTarget 返回其事件監聽器觸發該事件的元素。
eventPhase 返回事件傳播的當前階段。
target 返回觸發此事件的元素(事件的目標節點)。
timeStamp 返回事件生成的日期和時間。
type 返回當前 Event 對象表示的事件的名稱。
initEvent() 初始化新建立的 Event 對象的屬性。
preventDefault() 通知瀏覽器不要執行與事件關聯的默認動做。
stopPropagation() 再也不派發事件(經常使用於阻止事件冒泡)。

閱讀原文this

參考資料:spa

事件流理解

javascript event(事件對象)詳解

DOM 事件深刻淺出(一)

相關文章
相關標籤/搜索