事件基本概念
事件類型:用來說明發生什么類型事件的字符串,即事件名。
事件目標:發生事件的對象。當談論事件時,會同時指明類型和目標。
事件處理程序:處理或響應事件的函數,即事件監聽程序。
事件對象:與特定事件相關并且包含有關該事件詳細信息的對象。事件對象作為參數傳遞給事件處理程序(IE8之前的瀏覽器通過Event獲取事件對象)。
事件傳播:事件發生時,事件會由window
發出,不斷經過下一級節點直到目標節點,到達目標節點后,事件會按原路線返回window
,事件從目標節點返回window
的過程就是事件傳播,又稱冒泡階段。在事件傳播階段可以通過事件對象阻止事件傳播。
事件捕獲: 事件發生時,事件會由window
發出,不斷經過下一級節點直到目標節點,這一過程就是事件捕獲,又稱捕獲階段。在事件捕獲階段可以通過事件對象阻止事件捕獲。IE8之前的瀏覽器不支持事件捕獲。
常見事件類型
1.Window事件
發生在瀏覽器窗口上的事件,部分事件的事件類型會與文檔中的某些事件類型同名,包括文檔以及外部資源完全加載時觸發的load
事件;瀏覽器窗口文檔跳轉到新文檔時觸發unload
事件,該事件觸發時不影響文檔跳轉;在文檔跳轉之前如果需要征得用戶同意,可以使用beforeunload
事件;瀏覽器窗口加載文檔過程中出錯時觸發error
事件;瀏覽器窗口尺寸改變時觸發resize
事件,滾動條滾動時觸發scroll
事件;瀏覽器窗口獲取焦點或者失去焦點時,分別觸發focus
事件,blur
事件;
2.DOM事件
主要有表單事件,鼠標事件,鍵盤事件,文本事件,文檔加載事件。
表單事件包括提交表單時觸發submit
事件;重置表單時觸發reset
事件;表單元素內容修改時觸發change
事件;得到焦點,失去焦點時觸發focus
事件,blur
事件;表單元素的點擊時觸發click
事件等;
鼠標事件包括點擊鼠標時觸發click
事件;移動鼠標時觸發mousemove
事件;按下,釋放鼠標按鍵時觸發mousedown
事件,mouseup
事件;點擊右鍵時觸發contextmenu
事件,可以用來修改上下文菜單;連續點擊兩次鼠標按鍵時觸發dblclick
事件;鼠標滑到元素上,離開元素時觸發mouseover
事件,mouseup
事件,IE中對應mouseenter
事件,mouseleave
事件;
鍵盤事件包括按下,釋放按鍵時觸發的keydown
事件,keyup
事件;keydown
事件與keyup
事件之前會觸發keypress
事件;
文本事件,使用webkit內核的瀏覽器支持textInput
事件,該事件在產生可打印字符時觸發;
3.HTML5事件
主要是指HTML5標準化的事件以及新增的事件。
事件傳播
一個事件發生時,是事件先從文檔根節點流向事件目標,然后在事件目標上觸發事件,然后再回溯到文檔根節點,即事件傳播有三個階段,從文檔根節點流向事件目標是捕獲階段,到達事件目標是目標階段,然后從事件目標到文檔根節點是冒泡階段(IE8之前的瀏覽器不支持捕獲階段,所以其事件傳播,只有冒泡階段)。完整流程如下圖。
這里有一個Demo形象的模擬了事件傳播過程。
事件代理
瀏覽器都支持冒泡階段,我們可以利用瀏覽器的冒泡機制,通過監聽父級節點來實現監聽子節點的功能,這就是事件代理的概念。
使用事件代理的好處:
1.減少事件綁定次數,提高頁面性能;
2.可以監聽動態變化的DOM
結構,前提是父級節點不是動態變化的,子節點可以動態變化。
原理是在父級節點綁定相應事件處理程序,當對應事件在子節點觸發時通過冒泡階段把事件傳遞到父節點,在父節點觸發事件處理程序,再根據事件對象的target
屬性可以獲取到是哪個事件目標,然后就可以根據不同的事件目標,來實現不同的業務邏輯。
事件監聽(綁定,注冊)
主要有以下方式來注冊事件處理程序:
1.通過設置事件目標的事件屬性,這些事件屬性主要是由“on+事件名”組成。
例如:
document.getElementByTagName("a").onclick = function(){console.log("This is a click event");};
通過這種方式注冊事件處理程序,同一個事件目標一次只能注冊一個事件處理程序。
2.通過設置標簽屬性注冊事件處理程序。
例如:
<a onclick="console.log('This is a click event')"></a>
通過這種方式只需要把函數體賦值給事件屬性即可,同樣的這種方式一次也只能注冊一個事件處理程序。
3.支持標準事件模型的瀏覽器(IE8以及IE8之前的瀏覽器除外)中,事件目標對象中都有一個addEventListener()
方法,可以使用這個方法給事件目標注冊事件處理程序。使用這個方法一次可以給事件目標注冊多個不同的事件處理程序,使用不同的事件處理程序參數多次調用即可,觸發時根據注冊順序先后執行事件處理程序。相同的事件處理程序參數多次調用這個方法注冊,也只能注冊一次。
這個方法的完整定義:
element.addEventListener(event, function, useCapture)
event 必傳參數 指定事件名
function 必傳參數 事件處理程序
userCapture 可選參數 默認為false,指定事件處理程序在冒泡階段執行;ture,指定事件處理程序在捕獲階段執行
4.不支持標準事件模型的瀏覽器(IE8以及IE8之前的瀏覽器)中,事件目標可以使用attachEvent()
方法來注冊事件處理程序。相同的事件處理程序使用這個方法可以被注冊多次。
這個方法的完整定義:
element.attachEvent(event, function, useCapture)
event 必傳參數 指定 "on"+事件名
function 必傳參數 事件處理程序
由于IE8以及IE8之前瀏覽器不支持事件捕獲,所以這個方法只有兩個參數。
注意:IE9,IE10即支持
addEventListener()
方法又支持attachEvent()
方法來注冊事件處理程序,但是IE8,IE7,IE6,IE5瀏覽器只支持attachEvent()
方法注冊事件處理程序。
事件調用順序
1.通過方式1,2注冊的事件處理程序優先執行。
2.通過方式3注冊的事件處理程序按照注冊順序執行。
3.通過方式4注冊的事件處理程序執行順序不定,(測試發現IE9,IE10按照注冊順序正序執行,IE8按照注冊順序倒序執行)。
事件解綁,注銷
通過方式1,2注冊的事件無法解綁。
通過方式3注冊的事件處理程序可以通過 removeEventListener()
方法解綁, removeEventListener()
方法有三個參數,第一個參數與addEventListener()
方法一樣,需要傳事件名;第二個參數需要傳 用addEventListener()
方法注冊的事件處理程序函數名,即想要解綁addEventListener()
方法注冊的事件處理程序,那么在注冊時必須用事先聲明好的函數,不能用匿名函數注冊;第三個參數與addEventListener()
方法的第三個參數一樣。
通過方式4注冊的事件處理程序可以通過detachEvent()
方法解綁,detachEvent()
方法參數與attachEvent()
方法參數一樣,使用時和 removeEventListener()
方法類似。
事件取消
1.取消發生該事件時瀏覽器的默認操作
通過方式1,2注冊的事件處理程序,可以直接返回false
來告訴瀏覽器不要執行事件相關的默認操作。
通過方式3注冊的事件處理程序,可以直接調用事件對象的preventDefault()
方法來告訴瀏覽器不要執行事件相關的默認操作。
通過方式4注冊的事件處理程序,可以通過設置事件對象的returnValue
屬性為false
來告訴瀏覽器不要執行事件相關的默認操作。
2.取消事件傳播
通過方式1,2注冊的事件處理程序,不能取消事件傳播
通過方式3注冊的事件處理程序,可以直接調用事件對象的stopPropagation()
方法來阻止事件傳播。
通過方式4注冊的事件處理程序,可以直接設置事件對象的cancelBubble
屬性為true
來阻止事件傳播。
自定義事件
對于支持標準事件模型的瀏覽器可以通過以下方式實現自定義事件
初始化事件類型
var event = new Event('myEvent');
或者
var event = document.createEvent('Event');
event.initEvent('myEvent',true,true);
綁定事件
element.addEventListener('myEvent',function(){});
解綁事件
element.removeEventListener('myEvent',funcName);
觸發事件
element.dispatchEvent(event);
針對支持標準事件模型的瀏覽器處理事件時大體流程相似,主要的區別有兩點,自定義事件需要初始化事件類型,以及使用dispatchEvent
方法觸發事件
IE瀏覽器注冊自定義事件可以通過IE瀏覽器的私有的事件屬性propertychange
實現,具體參考漫談js自定義事件、DOM/偽DOM自定義事件
如果引用了jquery
,使用自定義事件就比較簡單了
綁定事件
element.on("myEvent",function(){});
解綁事件
element.off("myEvent");
觸發事件
element.trigger("myEvent");
自定義事件與內置事件的區別關注點不一樣,自定義事件關注的是執行事件的標簽,觸發時機由程序控制;而內置事件關注的是觸發事件的標簽,觸發時機由瀏覽器控制。自定義事件詳細可以參考 Introducing custom events
資料來源
1.js權威指南
2.http://blog.jobbole.com/52430/
3.http://www.admin10000.com/document/6089.html
4.http://learn.jquery.com/events/introduction-to-custom-events/