所謂的標準事件流指的的:EMCAScript標準規定事件流包含三個階段,分別爲事件捕獲階段,處於目標階段,事件冒泡階段。html
下面是一段html代碼,根據代碼來講明標準事件流。前端
<!DOCTYPE HTML> <html> <body> <div> <button>click</button> </div> </body> </html>
在上面的代碼中,若是點擊按鈕button,則標準事件觸發分別經歷如下三個階段:java
事件觸發一次經歷三個階段,因此咱們在一個元素上註冊事件也就能夠在對應階段註冊事件,移除事件也一樣。瀏覽器
target.addEventListener(type, listener, useCapture); //標準註冊事件函數
//target:target: 文檔節點、document、window 或 XMLHttpRequest。 //函數的參數,分別爲 註冊事件類型---type不包含on,事件的回調函數,事件註冊在捕獲期間仍是冒泡期間
//例如:給button註冊onclick事件,要是在捕獲階段註冊,則 button.addEventListener("click",function(){},true);
target.removeEventListener(type, listener, useCapture); //在某一個元素上撤銷已註冊的事件。 這裏強調的是 這裏的函數必須與已註冊的函數是同一個函數!
雖然大部分的瀏覽器都遵循着標準,可是在IE瀏覽器中,事件流倒是非標準的。IE中事件流只有兩個階段: 處於目標階段,冒泡階段。 前端框架
上面的HTML結構,若是是在IE中,事件流執行時如圖所示:框架
對應着在IE中的事件註冊和撤銷事件函數:dom
target.attachEvent(type, listener); //target: 文檔節點、document、window 或 XMLHttpRequest。
//函數參數: type----包含on.type通常爲「onclick」,"onkeydown"
// listener:事件觸發時的回調函數。
target.detachEvent(type,listener); //參數與註冊參數相對應。
由於,IE中事件流沒有捕獲階段,因此相應的在註冊事件和撤銷事件時比標準註冊事件少一個參數。函數
爲何要單獨提出事件的執行順序? 是由於一些事件有其默認的行爲,好比在文本框中按下鼠標左鍵,文本框文本框得到焦點;點擊一個超連接,超連接進行跳轉。 那麼,事件的執行順序是怎樣的呢?工具
通常事件的執行順序: 事件的捕獲階段====>處於目標階段====>事件的冒泡階段====>事件的默認行爲。this
正由於事件的默認行爲是最後執行的,咱們才得以機會阻止事件的默認行爲。
以下,阻止文本框獲取焦點:
//阻止文本框獲取焦點
var input=document.getElementById("inputText"); input.onmousedown=function(event){ event=event||window.event; if(event.preventDefault){ //非IE瀏覽器阻止事件默認行爲 event.preventDefault(); }else{ event.returnValue=false;//IE瀏覽器阻止事件默認行爲 } }
由於IE中瀏覽器註冊事件比較特殊,下面是一個跨瀏覽器註冊函數。
var EventUtil = {
addEventListener: function (element, type, callback) { //註冊事件,由於瀏覽器的兼容性考慮,註冊事件通常都是註冊在事件的冒泡階段
if (element.addEventListener) {
element.addEventListener(type, callback, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, callback);
} else {
element['on' + type] = callback;
}
},
removeEventListener: function(element, type, callback) { //撤銷事件
if (element.removeEventListener) {
element.removeEventListener(type, callback, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, callback);
} else {
element['on' + type] = null;
}
}
};
經過javaScript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序的屬性。這種爲事件處理程序賦值的方法是在第四代Web瀏覽器中出現的,並且至今仍然爲全部如今瀏覽器支持。緣由主要有兩點: 1.簡單 2.具備跨瀏覽器優點。
每一個元素(window和document)都有本身的事件處理程序屬性,這些屬性一般所有小寫,例如 onclick, onmousedown.
var btn = document.getElementById('mybtn'); btn.onclick = function () { alert('click'); }
DOM0級事件有其自身的侷限性,
1.那就是某一個屬性只能賦值給一個函數,也就致使在某一個元素上的某一個事件屬性只能對應着一個函數。屢次註冊時,已最 後一次註冊爲準。
2.DOM0級事件所有都是默認在冒泡階段執行。
咱們在第一部分所定義的跨瀏覽註冊事件函數,就是一個DOM2級註冊事件。DOM2級註冊事件相比於DOM0級的優點就在於其能夠屢次註冊,而且執行順序與註冊順序一致。
var btn = document.getElementById('mybtn'); function fun1(){ alert("1");} function fun2(){ alert("2");}
EventUtil.addEventListener(btn,"click",fun1); //註冊事件
EventUtil.addEventListener(btn,"click",fun1); //觸發事件的時候會 先彈出 1 在彈出 2
若是不考慮IE瀏覽器,咱們還能夠在事件的捕獲階段,註冊事件,可是通常因兼容性考慮,咱們不多在事件的捕獲階段註冊事件。
在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含着全部事件有關的信息。
例如,單擊事件中會包含鼠標的位置信息,鍵盤觸發的事件中會包含按下的鍵位有關的信息。
全部的瀏覽器都支持event,但支持的方式卻有不一樣。
屬性 | 類型 | 讀寫 | 描述 |
---|---|---|---|
bubbles | boolean | 只讀 | 返回布爾值,指示事件是不是起泡冒泡 |
cancelable | boolean | 只讀 | 返回布爾值,指示事件是否可擁可取消的默認動做。 |
currentTarget | Element | 只讀 | 返回其事件監聽器觸發該事件的元素。 |
eventPhase | Intenger | 只讀 | 返回事件傳播的當前階段。 |
target | Element | 只讀 | 返回觸發此事件的元素(事件的目標節點)。 |
timeStamp | Date | 只讀 | 返回事件生成的日期和時間。 |
type | String | 只讀 | 返回當前 Event 對象表示的事件的名稱。 |
trusted | boolean | 只讀 | 該事件是不是瀏覽器生成(true表明是,false表明是開發人員建立 |
preventDefault | Function | 只讀 | 取消事件的默認行爲在cancelable=true時有效 |
stopPropagation | Function | 只讀 | 取消事件的捕獲或者冒泡行爲在bubbles=true時有效 |
在事件處理程序內部,對象this始終指向currentTarget的值,而target則只包含事件的實際目標。
屬性 | 類型 | 讀寫 | 描述 |
---|---|---|---|
cancelBubble | boolean | 讀/寫 | 返回布爾值,指示事件是不是起泡冒泡 |
returnValue | boolean | 讀/寫 | 返回布爾值,指示事件是否可擁可取消的默認動做。 |
srcElement | Element | 只讀 | 返回其事件監聽器觸發該事件的元素。 |
type | String | 只讀 | 被觸發事件的類型 |
上面的這些屬性,是任何一個事件均會具備的屬性。
在IE中有些srcElement對應着target;
執行event.returnValue=false對應着event.preventDefault();
執行event.cancelBubble=true對應着event.stopPropagation();
同時對於一些相關屬性IE 好比 relatedTarget屬性對應IE中的fromElement和toElement.屬性.
由於IE和標準瀏覽器的不一樣,因此爲了克服這樣或者那樣的問題,如今編寫一個工具包克服兼容性的問題:
1 var EventUtil = { 2 addEventListener: function (element, type, callback) { //註冊事件,由於瀏覽器的兼容性考慮,註冊事件通常都是註冊在事件的捕獲階段 3 if (element.addEventListener) { 4 element.addEventListener(type, callback, false); 5 } else if (element.attachEvent) { 6 element.attachEvent('on' + type, callback); 7 } else { 8 element['on' + type] = callback; 9 } 10 }, 11 getEvent:function(event){ //獲取事件 12 return event||window.event; 13 }, 14 getTarget:function(event){ //獲取事件的觸發目標 15 return event.target||event.srcElement; 16 }, 17 preventDefault:function(event){ //阻止事件的默認行爲 18 event.preventDefault?event.preventDefault():event.returnValue=false; 19 }, 20 stopPropagation:function(event){ //阻止事件冒泡 21 event.stopPropagation?event.stopPropagation:event.cancelBubble=true; 22 }, 23 removeEventListener: function(element, type, callback) { //撤銷事件 24 if (element.removeEventListener) { 25 element.removeEventListener(type, callback, false); 26 } else if (element.detachEvent) { 27 element.detachEvent('on' + type, callback); 28 } else { 29 element['on' + type] = null; 30 } 31 } 32 };
每一個事件在其被觸發時,都有一些其特有的屬性,好比鍵盤事件會有鍵位信息,鼠標事件會有會有位置信息。onmouseenter事件會有fromElement(IE)中,relatedTarget(非IE);onmouseover事件會有toElement(IE)中,relatedTarget(非IE).
詳情在W3C教程中有進一步的敘述。W3C事件詳解
非IE瀏覽器
建立鼠標事件的方法是createEvent()傳入字符串「MouseEvent」.返回的對象有initMouseEvent()方法,這個方法有15個參數,分別與鼠標事件中某個典型的屬性一一對應。
參數 | 類型 | 描述 |
type | String | 要觸發的事件類型,例如‘click’。 |
bubbles | Boolean | 表示該事件是否可以被取消,針對鼠標事件模擬,該值應該被設置爲true。 |
cancelable | Boolean | 表示該事件是被取消 |
view | AbstractView | 抽象視圖:事件授予的視圖,這個值幾乎全是document.defaultView. |
detail | Intenger | 附加的事件信息這個初始化時通常應該默認爲0。 |
screenX | Intenger | 事件距離屏幕左邊的X座標 |
screenY | Intenger | 事件距離屏幕上邊的y座標 |
clientX | Intenger | 事件距離可視區域左邊的X座標 |
clientY | Intenger | 事件距離可視區域上邊的y座標 |
ctrlKey | Boolean | 表明ctrol鍵是否被按下,默認爲false。 |
altKey | Boolean | 表明alt鍵是否被按下,默認爲false。 |
shiftKey | Boolean | Boolean類型 : 表明shif鍵是否被按下,默認爲false |
metaKey | Boolean | 表明meta key 是否被按下,默認是false |
button | Intenger | 表示被按下的鼠標鍵,默認是零 |
relatedTarget | Elment | 事件的關聯對象只有在模擬mouseover 和 mouseout時用到 |
使用方法以下:
var btn=document.getElementById("mybtn"); var event=document.createEvent("MouseEvent"); event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null); btn.dispatchEvent(event); //在這一步會設置event.target,以及觸發事件類型
IE瀏覽器模擬鼠標事件
var event=document.createEventObject(); event.screenX=100; event.screenY=100; event.clientX=100; event.clientX=100; event.ctrlKey=false; btn.fireEvent("onclick",event); //在這一步會設置event.serElement,以及觸發事件類型
鍵盤模擬事件是在DOM3規範中定義的。火狐瀏覽器根據草案定義了DOM2級中模擬鍵盤事件。在這裏,咱們講述的是DOM3級規範,DOM3級不提倡使用oneypress事件。
DOM3標準
建立鍵盤事件的方法是createEvent()傳入字符串「KeyboardEvent」.返回的對象有initKeyEvent()方法,這個方法有如下參數:
參數 | 類型 | 描述 |
type | String | 要觸發的事件類型,例如"keydown". |
bubbles | Boolean | 表示該事件是否可以被取消,針對鼠標事件模擬,該值應該被設置爲true。 |
cancelable | Boolean | 表示該事件是被取消 |
view | AbstractView | 被授予事件的是圖. 一般值爲:document.defaultView. |
key | string | 按下的鍵對應的code. |
location | integer | 按下鍵所在的位置. 0 :默認鍵盤, 1 左側位置, 2 右側位置, 3 數字鍵盤區, 4 虛擬鍵盤區, or 5 遊戲手柄. |
modifiers | Boolean | 一個有空格分開的修飾符列表. |
repeat | integer | 一行中某個鍵被按下的次數 |
使用方式:
var textbox=document.getElementById("myTextBox"),event; if(document.implementation.hasFeature("KeyboardEvent",3.0)){ event=document.createEvent("KeyboardEvent"); event.initKeyboardEvent("keydown",true,true,document.defaultView,"a",0,"shift",0); textbox.dispatchEvent(event); }
並不是全部的瀏覽器都實現了DOM3標準,下面看一下各個瀏覽器時怎麼模擬鼠標事件。
FF瀏覽器
在FireFox中,調用createEvent()並傳入KeyEvents就能夠建立一個鍵盤事件。返回的事件對象會包含一個initKeyEvent()方法,這個方法接受一下10個參數。
參數 | 類型 | 描述 |
type | String | 要觸發的事件類型,例如"keydown". |
bubbles | Boolean | 表示該事件是否可以被取消,針對鼠標事件模擬,該值應該被設置爲true。 |
cancelable | Boolean | 表示該事件是被取消 |
view | AbstractView | 被授予事件的是圖. 一般值爲:document.defaultView. |
ctrlKey | Boolean | 表示是否按下了ctrl鍵位,默認值 false. |
altKey | Boolean | 表示是否按下了altl鍵位,默認值 false |
shiftKey | Boolean | 表示是否按下了shift鍵位,默認值 false. |
metaKey | Boolean | 表示是否按下了meta鍵位,默認值 false. |
KeyCode | Intenger | 被按下或者被釋放的鍵位. 這個參數對keydown和keyup有用 |
charCode | Intenger | 經過按鍵生成的ASCII編碼. 這個參數對keypress有用 |
//只適用於FF瀏覽器,在火狐瀏覽器中會在文本框中顯示A
var textbox=document.getElementById("myTextBox"); //建立事件對象 var event=document.createEvent("keyEvents"); //初始化事件對象 event.initKeyEvent("keypress",true,true,document.defaultView,false,false,false,false,65,65); //觸發事件 textbox.dispatchEvent(event);
非火狐非IE瀏覽器
在其餘瀏覽器中,則須要建立一個通用事件,而後再向通用事件中添加鍵盤事件的特有信息。
//在其餘瀏覽器中不能輸入文本,這是由於非瀏覽器建立的事件並不能精確的模擬事件。
//建立事件對象 var event=document.createEvent("Events"); //初始化事件對象 event.initEvent(type,bubble,cancelable);
//初始化事件信息 event.view=document.defaultView; event.altKey=false; event.ctrlKey=false; ..... event.keyCode=65; event.charCode=65;
//觸發事件
textbox.dispatchEvent(event);
IE瀏覽器
IE瀏覽器建立鍵盤事件和建立鼠標事件有點相似。以下所示:
var event=document.createEventObject(); event.altKey=false; event.ctrlKey=false; event.shiftKey=false; event.keyCode=65; textbox.fireEvent("onkeydown",event);
DOM3級還定義了"自定義事件"。自定義事件不一樣時DOM原生觸發的,它的目的是讓開發人員建立本身的事件。要建立新的自定義事件;
非IE瀏覽器
能夠調用createEvent("CustomEvent")返回的對象有一個名爲initCustomEvent()方法,接受以下四個參數:
參數 | 類型 | 描述 |
type | String | 要觸發的事件類型,例如"keydown". |
bubbles | Boolean | 表示該事件是否可以被取消,針對鼠標事件模擬,該值應該被設置爲true。 |
cancelable | Boolean | 表示該事件是被取消 |
detail | Boolean | 保存在event對象的detail屬性中 |
//文檔結構
<!DOCTYPE HTML> <html> <body> <div> <button id="button">click</button> <input type="text" id="inputText"/> </div> </body> </html>
//節本
var input=document.getElementById("inputText"); EventUtil.addEventListener(input,"myevent",function(event){ event=EventUtil.getEvent(event); alert(event.detail.message); //訪問detail中的信息 });//註冊時事件 var button=document.getElementById("button"); button.onclick=function(){ if(document.implementation.hasFeature("CustomEvents","3.0")){ var event=document.createEvent("CustomEvent"); event.initCustomEvent("myevent",true,false,{message:"helloworld"}); input.dispatchEvent(event); } //經過button按鈕觸發事件
}
IE瀏覽器自定義事件
//IE中document.createEventObject()方法不支持自定義的DOM事件....咱們在有些前端框架中之全部可以實現自定義事件的各類瀏覽器兼容都是由於他們內部重寫了一套事件機制來控制,才使得咱們能夠在各個瀏覽器上自定義事件。