盤點JavaScript中的事件及事件的三種模型
前言
我們知道在很多編程語言都有事件這個概念,在JavaScript中同樣存在事件,原因也很簡單,我們知道HTML是頁面結構層,相當于人的骨架;
CSS是樣式層,相當于人的外形;但是它是靜態的,一個人應該能動,動起來,所以產生了JavaScript;JavaScript就是用來控制頁面元素,與用戶產
生動態交互效果,才構成了如今這豐富多樣化的界面。今天我們就來認識一下js當中的事件;
一、事件相關概念
事件:指用戶的鼠標動作和鍵盤動作,document的load和unloaded,事件被封裝成一個event對象,包含了該事件發生時的所有相關信息(event的屬性)以及可以對事件進行的操作(event的方法)。
- 比如點擊頁面上一個按鈕,產生的event對象如下:
以上可以看到是一個MouseEvent對象,包含了一系列屬性,如鼠標點擊的位置等。
- 敲擊鍵盤時產生的event對象
- window.onload監聽函數中打印出event對象如下:
注意:Event 類是MouseEvent、KeyboardEvent的父類。
二、事件對象常用屬性和方法
2.1事件定位相關屬性
MouseEvent對象里的屬性,很多帶X/Y,它們都和事件的位置相關。具體包括:x/y、clientX/clientY、pageX/pageY、screenX/screenY、layerX/layerY、offsetX/offsetY 六對;之所以能有這么多是因為各瀏覽器廠商在版本更迭的時候產生了很多不一致:
以移動鼠標為例:
x屬性 | Y屬性 | 功能 |
x | Y | 距瀏覽器可視區域(工具欄除外區域)左/上的距離; |
clientX | clientY | 距瀏覽器可視區域(工具欄除外區域)左/上的距離(同上); |
screenX | screenY | 距計算機顯示器左/上的距離,拖動你的瀏覽器窗口位置可以看到變化; |
offsetX | offsetY | 距有定位屬性的父元素左/上的距離;(不計算邊框) |
pageX | pageY | 距頁面左/上的距離,它與clientX/clientY的區別是不隨滾動條的位置變化; |
layerX | layerY | 距有定位屬性的父元素左/上的距離(計算邊框); |
之所以有那么多值一樣的情況,就是由于瀏覽器兼容的原因, 針對于瀏覽器對于不同屬性的兼容情況如下所示;(+支持,-不支持)
瀏覽器 | offsetX/offsetY | x/y | layerX/layerY | pageX/pageY | clientX/clientY | screenX/screenY |
W3C | - | - | - | - | + | + |
IE | + | + | - | - | + | + |
Firefox | - | - | + | + | + | + |
Opera | + | + | - | + | + | + |
Safari | + | + | + | + | + | + |
chrome | + | + | + | + | + |
說明:詳情可查
https://www.caniuse.com/
2.2其他常用屬性
- target:發生事件的節點;
- currentTarget:當前正在處理的事件的節點,在事件捕獲或冒泡階段;
- timeStamp:事件發生的時間,時間戳。
- bubbles:事件是否冒泡。
- cancelable:事件是否可以用preventDefault()方法來取消默認的動作;
- keyCode:按下的鍵的值;
2.3 event對象的方法
- event. preventDefault(): 阻止元素默認的行為,如鏈接的跳轉、表單的提交;
- event. stopPropagation(): 阻止事件冒泡;
- event.initEvent(): 初始化新事件對象的屬性,自定義事件會用,不常用;
- event. stopImmediatePropagation(): 可以阻止掉同一事件的其他優先級較低的偵聽器的處理很少使用;
三、事件的三種模型
3.1 原始事件模型(DOM0級)
在原始事件模型中,事件發生后沒有傳播的概念,沒有事件流。事件發生,馬上處理。監聽函數只是元素的一個屬性值,通過指定元素的屬性值來綁定監聽器。書寫方式有兩種:
1.HTML代碼中指定屬性值:
<input type="button" notallow="func1()" />
2.在js代碼中指定屬性值:
document.getElementsByTagName(‘input’)[0].onclick = func1
優點:所有瀏覽器都兼容
缺點:
- 邏輯與顯示沒有分離;
- 相同事件的監聽函數只能綁定一個,后綁定的會覆蓋掉前面的,如:a.onclick = func1; a.onclick = func2;將只會執行func2中的內容;
- 無法通過事件的冒泡、委托等機制完成更多事情;
3.2 IE事件模型
“IE不把該對象傳入事件處理函數,由于在任意時刻只會存在一個事件,所以IE把它作為全局對象window的一個屬性”,用IE8執行了代碼alert(window.event),結果彈出是null,說明該屬性已經定義,只是值為null(與undefined不同),代碼如下;
window.onload = function (){alert(window.event);}
setTimeout(function(){alert(window.event);},2000);
第一次彈出【object event】,兩秒后彈出依然是null。由此可見IE是將event對象在處理函數中設為window的屬性,一旦函數執行結束,便被置為null了;
IE的事件模型只有兩步:
- 先執行元素的監聽函數,
- 然后事件沿著父節點一直冒泡到document。
IE模型下的事件監聽方式比較獨特,綁定監聽函數的方法是:
attachEvent( "eventType","handler");//其中evetType為事件的類型,
如onclick,注意要加’on’。解除事件監聽器的方法是:
detachEvent("eventType","handler" )
IE的事件模型已經可以解決原始模型的三個缺點,但其自己的缺點就是兼容性,只有IE系列瀏覽器才可以這樣寫。
3.2 DOM2事件模型
此模型是W3C制定的標準模型,既然是標準,現代瀏覽器(指IE6~8除外的瀏覽器)都已經遵循這個規范。W3C制定的事件模型中,一次事件的發生包含三個過程:
- capturing phase:事件捕獲階段。事件被從document一直向下傳播到目標元素,在這過程中依次檢查經過的節點是否注冊了該事件的監聽函數,若有則執行;
- target phase:事件處理階段。事件到達目標元素,執行目標元素的事件處理函數;
- bubbling phase:事件冒泡階段。事件從目標元素上升一直到達document,同樣依次檢查經過的節點是否注冊了該事件的監聽函數,有則執行;
所有的事件類型都會經歷captruing phase但是只有部分事件會經歷bubbling phase階段,例如submit事件就不會被冒泡。
標準的事件監聽器綁定:
addEventListener("eventType","handler","true|false");
其中eventType指事件類型。第二個參數是處理函數,第三個即用來指定是否在捕獲階段進行處理,一般設為false來與IE保持一致。
監聽器的解除也類似:
removeEventListner("eventType","handler","true!false");
以上便是事件的三種模型,我們在開發的時候需要兼顧IE與非IE瀏覽器,所以注冊一個監聽器應該這樣寫:
var a = document.getElementById('a');
if(a.attachEvent){
a.attachEvent('onclick',func);
}
else{
a.addEventListener('click',func,false);
}
四、總結
本文我們就JavaScript事件做了基本介紹,認識了事件的相關概念,事件的常用屬性和方法,以及事件的三種模型,想要完成復雜的界面動態交互效果,事件的使用至關重要,想要深入了解事件的小伙伴可以參考官方手冊。
http://www.javascriptcn.com/