1. 事件是什么
DOM事件即為Event對象。Event對象代表事件的狀態,比如事件在其中發生的元素、鍵盤按鍵的狀態、鼠標的位置、鼠標按鈕的狀態。
JavaScript的事件機制也是一個標準的觀察者模式(Observer Pattern)的應用,包含事件的訂閱者(Subscriber)和事件發布者(Publisher),通過監聽對象事件來執行事件處理程序(callback)。
通常事件與函數結合使用,函數不會在事件發生前被執行。
2. 事件綁定
要讓javascript對用戶做出相應,首先要對 DOM 元素綁定事件處理函數。javascript一共有三種方式可以為DOM元素注冊事件處理函數。
通過HTML 屬性
<button onclick="console.log('Hello world!')">通過DOM 元素屬性(DOM level 0 事件)
<button id='event'>Event</button>
<script>
var button = document.querySelector('#event')
button.onclick=function(){
console.log("Hello world!")
}
</script>通過EventTarget.addEventListener(DOM level 2 事件)
<button id='event'>Event</button>
<script>
var myButton = document.getElementById('event')
myButton.addEventListener('click', function(){
console.log('Hello world');
}, false);
</script>
在javascript中,后兩種方法(DOM level 0 事件和DOM level 2 事件)為最常見的綁定事件方法。其中DOM level 0 事件綁定只能添加一個,添加多個則后面會覆蓋前面。而DOM level 2 事件綁定可以添加多個事件。
3. 事件階段
一般的,事件分為三個階段:捕獲階段、目標階段和冒泡階段。
- 捕獲階段(capture phase)
事件的第一個階段是捕獲階段。事件從文檔的根節點流向目標對象節點。途中經過各個層次的DOM節點,并在各節點上觸發捕獲事件,直到到達事件的目標節點。捕獲階段的主要任務是建立傳播路徑,在冒泡階段,事件會通過這個路徑回溯到文檔跟節點。
- 目標階段(target phase)
當事件到達目標節點的,事件就進入了目標階段。事件在目標節點上被觸發,然后會逆向回流,直到傳播至最外層的文檔節點。
- 冒泡階段(bubble phase)
事件在目標元素上觸發后,并不在這個元素上終止。它會隨著DOM樹一層層向上冒泡,回溯到根節點。
冒泡過程非常有用。它將我們從對特定元素的事件監聽中釋放出來,如果沒有事件冒泡,我們需要監聽很多不同的元素來確保捕獲到想要的事件。
ie默認支持事件冒泡階段執行,其它瀏覽器默認支持事件捕獲階段執行。
支持W3C標準的瀏覽器在添加事件時用addEventListener(event,fn,useCapture)方法,基中第3個參數useCapture是一個Boolean值,用來設置事件是在事件捕獲時執行,還是事件冒泡時執行,默認值為false。<strong>(永遠不要用true)</strong>
<!--example-->
button.addEventListener('click', fn, true) // 捕獲階段執行(永遠不用)
button.addEventListener('click', fn, false) // 冒泡階段執行(默認)
4. 事件委托
在處理傳統事件時,你按照需要為每一個元素添加事件監聽器(如對多個<li>進行監聽)。但是事件監聽器是占內存的,如果處理不當的話會導致性能下降和內存溢出。
為了解決這個問題,JavaScript事件代理可以把事件處理器添加到一個父元素上,這樣就避免了把事件處理器添加到多個子元素上。
<!--example-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOM Event</title>
<style>
li{
border: 1px solid black;
}
ul{
background-color: red;
padding: 20px;
}
</style>
</head>
<body>
<ul>
<li>iPhone</li>
<li>iPad</li>
<li>Macbook</li>
<li>iPod</li>
</ul>
</body>
<script>
var parent = document.querySelector('ul')
parent.addEventListener('click',function(e){
var el = e.target
//console.log(e.target)
while(el.tagName !== 'LI'){
if(el === parent){
el = null
break
}
el = el.parentNode
console.log(el)
}
if(el){
console.log(el.innerText)
}else{
console.log('未命中')
}
})
</script>
</html>
利用事件委托點擊<li>時監聽返回標簽中的文本元素,點擊<ul>則輸出‘未命中’。