事件
JS 與 HTML 之間交互即是經過事件實現的。事件就是文檔或者瀏覽器窗口中發生的一些特定的交互瞬間。可使用監聽器來預約事件,以便事件發生的時候執行相應的代碼。
1. 事件流
事件流描述的是從頁面中接收時間的順序,IE的爲冒泡流,而Netscape爲事件捕獲流。
1.1 事件冒泡
那麼事件流的順序按照冒泡爲
div -> body -> html -> Document
須要注意的是 只有 IE9, FF, Chrome 和 Safari 會一直冒泡到 window
1.2 事件捕獲
事件捕獲則是一個相反的流程
Document ->html -> body -> div
依次從上到下傳遞事件流。、
1.3 DOM 事件流
DOM2級事件 中規定事件流包括3各階段:事件捕獲,處理目標和事件冒泡。
對於IE,直到IE9才支持該DOM2級事件。
2. 事件處理程序
事件就是用戶或者瀏覽器自身執行某種動做,響應某個事件的函數就稱之爲事件處理程序。
2.1 HTML事件處理程序
該操做經過指定 onclick 特性並將一些 JS 代碼做爲它的值來進行定義。
須要注意的地方就是 HTML事件中 this 的指向問題
如上的 input 代碼 當 onclick="alert(this.value)",沒有問題會彈出 "Click Me" 的結果。
可是一旦 onclick="showValue()"再定義
function showValue(){
alert(this.value);
}
結果爲 undefined。 由於這裏的this 已經指向到 window,若是須要將函數定義在外部全局中,而且須要使用到所點擊的節點DOM,那麼就在HTML的JS代碼中傳入 this 便可,onclick="showValue(this)",在處理函數。
2.2 DOM 0級事件處理程序
經過JS指定事件處理程序傳統方式就是將函數賦給一個事件處理程序屬性。簡單又有跨瀏覽器優點。
函數內部的 this 會指向當前元素
刪除事件只須要將事件屬性置爲 null 便可。
2.3 DOM 2級事件處理程序
DOM 2級事件 定義了2個方法, addEventListener 和 removeEventListener 。參數有三個, 處理的事件名,事件函數以及是不是捕獲階段的布爾值。
在此的事件函數是使用匿名函數的方式傳入,因此就不能在使用 removeEventListener 來解除綁定了,由於就算傳入了同樣的匿名函數,也是指向不一樣的函數,因此但願使用 remove 的,必須在add事件的時候使用變量引用傳入。
還有就是對於一個元素的一個屬性上能夠綁定多個事件,而且是按照綁定的順序執行的。addEventListener添加的事件只能使用 removeEventListener 來解綁,不能使用 0級事件處理程序的方式來解除事件綁定。
(IE9, FF,Safari, Chrome, Opera 支持 DOM2級)
2.4 IE事件處理程序
IE實現的與DOM中相似的兩個方法 attachEvent 和 detachEvent 接受兩個參數 事件處理程序名稱 和 事件處理程序函數。 其第一個參數爲 on 開頭,如 onclick,onsubmit等。
在IE中使用attachEvent與使用DOM0級方法最大的區別是事件處理程序的做用域。DOM0級中事件處理程序會在所屬元素的做用域內運行,可是在 attachEvent 方法下,事件處理程序會在全局做用於下運行,this會指向於window。
在對於編寫跨瀏覽器的代碼時,記住這點很重要。
還有一個與標準的DOM2級不一樣的是,在一個元素添加多個事件處理程序的時候,addEventListener是按照綁定的順序先綁定的先執行原則觸發 事件處理程序的,可是 attachEvent 是先執行最近綁定的事件的,即執行順序上與 addEventListener 相反。
在點擊後,先彈出 「Helloworld!」,然後 「Clicked」。
2.5 跨瀏覽器的事件處理程序
這邊只是簡單的提供了一個兼容方案,固然沒有很細緻的考慮其餘的好比IE中事件處理程序的做用域問題,以及綁定多個事件的執行順序問題。
3. 事件對象
在觸發DOM上的某個事件的時候,會產生一個事件對象event,該對象中包含了全部與事件有關的信息。例如鼠標點擊時刻鼠標的位置,鍵盤按下有關於鍵的信息等。
3.1 DOM中的事件對象
兼容DOM的瀏覽器無論使用 DOM0級仍是DOM2級都會將 event 事件對象傳入。
event 對象包含與建立他的特定時間有關的屬性和方法,觸發的事件類型不同可用的屬性和方法也不同,不過全部的又會有如下屬性:
在事件處理程序內部,this 始終指向 currentTarget的值, 對於 target 只包含事件的實際目標,當直接將事件處理程序指定給目標元素,那麼三個值就是相等的。
以下,將事件處理程序綁定在 body上
也能夠看作提升效率的 事件委託 的雛形。
event 事件對象中 preventDefault() 來取消默認行爲,好比 a 標籤的跳轉行爲等,stopPropagation() 方法使得事件中止在DOM中的傳播,取消進一步的事件捕獲或者冒泡。
注意,只有在事件處理程序執行期間event事件對象纔會存在,一旦事件結束,event對象就會銷燬。
3.2 IE中的事件對象
以前所說的均是標準DOM下的方式, IE對於事件對象有必定的不一樣,可是整體上是一致的。在DOM 0級下,event對象做爲window的一個屬性存在
event並非直接存在於事件處理程序之中的,而須要獲取到 window.event 再進行使用。在attenchEvent中,event對象就會被做爲參數傳入事件處理程序之中。
IE的event一樣也會包含一些屬性和方法
由於事件處理程序的做用域是更具指定他的方式來肯定的,全部不能認爲this會始終等於時間目標,使用 event.srcElement 比較保險。
3.3 跨瀏覽器的事件對象
雖然 DOM 與 IE 下event對象有所不一樣,可是基於類似性仍是能夠實現跨瀏覽器的解決方案來的。
4. 事件類型
DOM3級規定了如下
UI事件,當用戶與頁面上的元素交互的時候觸發。
焦點事件,當元素得到或者失去焦點的時候觸發。
鼠標事件,當用戶經過鼠標在頁面上執行操做的時候觸發。
滾輪事件,當用戶鼠標滾輪時觸發。
文本事件,當文檔中輸入文本的時候觸發。
鍵盤事件。
合成事件,當爲IME 輸入法編輯器 輸入字符的時候觸發。
變更事件,當低層的DOM結構發生變化的時候觸發。
DOM3級事件模塊在DOM2級事件模塊的基礎上從新定義了這些事件,也添加了新的事件,IE9在內主流瀏覽器均已支持DOM2級事件,IE9也支持部分DOM3事件。
4.1 UI事件
DOMActivate:表示元素已經被用戶操做過(DOM3中已經廢棄)。
load:當頁面徹底加載後在window上面觸發,當全部的框架都加載完畢的時候在框架集上觸發,當圖像加載完畢的時候在
上觸發,以及嵌入的。
css
unload:頁面徹底卸載的時候在window上面觸發。。。
abort:用戶中止下載過程,內容尚未加載完畢的時候。
error:當JS在window上發生錯誤的時候,圖像沒法加載的時候等。
select:當用戶選着文本框中的一個或者多姿字符時候觸發。
resize:窗口或者框架大小變化的時候觸發。
scroll:用戶滾動帶滾動條的內容的時候觸發。
須要注意的是,resize和scroll事件會在咱們調整窗口大小或者滾動的時候重複被觸發,因此應該儘可能保持事件處理程序的代碼簡單,或者作好邏輯處理。
4.2 焦點事件
blur:當元素失去焦點的時候觸發,事件不冒泡,各個瀏覽器兼容。
focus:當元素得到焦點的時候觸發,事件不冒泡,各個瀏覽器兼容。
focusin:當元素得到焦點的時候觸發,事件冒泡,各個瀏覽器兼容(IE5.5+ SF5.1+ Op 11.5+ chrome)。
focusout:當元素失去焦點的時候觸發,事件冒泡,各個瀏覽器兼容(IE5.5+ SF5.1+ Op 11.5+ chrome)。
那麼當焦點從一個元素移動到另一個元素的時候會依次觸發
1. focusout 在失去焦點的元素上觸發
2. focusin 在得到焦點的元素上觸發
3. blue 在失去焦點的元素上觸發
4. focusout 在得到焦點的元素上觸發
( Opera 上 還有DOMFocusIn 和 DOMFocusOut 事件 )
4.3 鼠標與滾輪事件
click: 用戶單擊鼠標按鈕時,或者按下回車鍵的時候。
dblclick: 用戶雙擊鼠標時候觸發。知道DOM3纔將其歸入標準。
mousedown:用戶按下任意鼠標按鈕,不能夠經過鍵盤觸發。
mouseup:用戶釋聽任意鼠標按鈕,不能夠經過鍵盤觸發。
mouseenter:在鼠標光標從元素外部移到元素範圍內的時候觸發,事件不冒泡,並且在移動到後代元素上的時候不觸發,DOM未定義該事件,DOM3歸入規範(IE,FF 9+,Opera等均支持)。
mouseleave:在鼠標光標從元素內部移到元素範圍外的時候觸發,事件不冒泡,並且在移動到後代元素上的時候不觸發,DOM未定義該事件,DOM3歸入規範(IE,FF 9+,Opera等均支持)。
mousemove:當鼠標在元素內部移動的時候重複的觸發。不能經過鍵盤觸發。
mouseout:鼠標在一個元素上方,而後首次移入到另一個元素的時候觸發。
mouseover:鼠標在一個元素外部,而後首次移入到該元素上方的時候觸發。
在雙擊鼠標的時候
mousedown -> mouseup -> click -> mousedown -> mouseup -> click ->dblclick
在對於IE8以前的版原本說會有一個小BUG, 雙擊時候會跳過第二個 mousedown 和 click。
檢測是否支持DOM2 DOM3級
document.implementation.hasFeature("MouseEvents", "2.0");
document.implementation.hasFeature("MouseEvent", "3.0");
還有一個跟蹤鼠標滾輪的事件 mousewheel 。
1. 客戶區座標位置
鼠標事件都是在瀏覽器視口中特定位子發生的,位子信息保存在事件對象的 clientX 與 clientY 屬性中。
可使用下面代碼獲取
該位置爲鼠標相對於客戶端視口的位子,不包括頁面滾動的距離,並不表示鼠標在頁面上的位置。
2. 頁面座標位置
頁面位置經過事件對象的 pageX 和 pageY 屬性來獲取,此座標爲頁面自己而非視口的左邊與頂邊計算的。
所以在頁面沒有滾動的狀況下,clientX,clientY 與 pageX,pageY的值是相等的。
IE8以及早期的版本不支持事件對象的頁面座標,不過能夠經過客戶區座標和滾動信息計算出來,須要使用 scrollLeft和scrollTop。
3. 屏幕座標位置
還有一個相對於屏幕的位子座標信息 screenX,screenY。
代碼以下:
4. 修改鍵
鼠標事件主要是由鼠標來觸發的,可是也有可能按下了其餘鍵。 狀態爲 shiftKey,ctrlKey,altKey和metaKey。
IE8及以前版本不支持。
5. 相關元素
相關元素指的是鼠標在發生 mouseover 和 mouseout 的時候還會涉及到其餘元素。
DOM經過event 的 relatedTarget 屬性提供相關元素的信息,只對 mouseover 和 mouseout 事件才包含,對於其餘事件均爲 null。
IE8以前版本沒有relatedTarget 屬性,可使用fromElement 和 toElement 來獲取相等意義的元素。
6. 鼠標按鈕
DOM的button 屬性
0:主鼠標鍵; 1:鼠標中間鍵或者滾輪鍵; 2:次鼠標鍵。
IE8及之前瀏覽器
7. 更多的事件信息
DOM2級事件規範還在event對象中提供了 detail 屬性,用於給出更多的事件信息。
對於鼠標事件來講,detail中包含了一個數值表示在給定的位子上發生了多少次的點擊。
8. 鼠標滾輪事件
從IE6起,就支持 mousewheel 事件,當用戶經過鼠標滾輪與頁面交互,在垂直方向上滾動頁面的時候都會觸發 mousewheel 事件。在滾動的時候還包含一個特殊的 wheelDelta 屬性,記錄的滾動的量值,爲120的倍數向前爲正,向後爲負。Firefox 支持一個名爲 DOMMouseScroll的相似事件,信息保存在detail屬性中,量值爲3的倍數。向前爲負,向後爲正。
9. 觸摸設備
因爲iOS, 安卓等設備較爲特殊,沒有鼠標因此
1. 不支持 dbclick,雙擊放大畫面,沒法改變該行爲。
2. 輕擊可單擊元素會觸發 mouseover 事件,若是此操做會致使內容變化將再也不有其餘事件發生。若是沒有變化 一次會觸發 mousedown mouseup 和 click。
3. mousemove 也會觸發 mouseover 和 mouseout 事件。
4. 兩個手指在屏幕上且頁面隨手指滾動的時候也會觸發 mousewheel 和 scroll 事件。
10. 無障礙性問題
4.4 鍵盤與文本事件
DOM3級事件 爲鍵盤事件制訂了規範
只有一個文本事件 textInput,是對keypress 的補充,使得將文本展示給用戶以前能夠攔截文本,在文本插入文本框以前就會觸發 textInput。
1. 鍵碼
keydown 和 keyup 的事件 event 對象的 keyCode 屬性中包含一個代碼,來顯示所按下的。
2. 字符編碼
IE9 以及其餘主流瀏覽器的 event 對象都支持一個 charCode,表明按下鍵的 ASCII編碼。
3. DOM3級變化
DOM3的鍵盤事件再也不包含 charCode 屬性, 而是分開爲 key 和 char 的兩個新屬性。
4. textInput 事件
當用戶在可編輯區域中輸入字符的時候就會觸發該事件,任何可得到焦點的元素均可以觸發 keypress,而是由可編輯區域才能夠觸發 textInput。
4.5 複合事件
是DOM3中的新添加的一類事件用於處理 IME 輸入序列。可讓用戶輸入鍵盤上沒有的符號。
4.6 變更事件
DOM2級變更事件能在DOM的某一部分發生變化的時候來給出提示。
對於瀏覽器支持狀況來講
1. 刪除節點
在使用removeChild() 或者 replaceChild() 從DOM中刪除節點的時候首先會觸發 DOMNodeRemoved事件。該事件的 event.target 就是被刪除的節點。
而 event.relatedNode則是對目標節點父節點的引用。
在上面HTML中,咱們刪除 ul 元素,就會依次:
1. 在 ul 上觸發 DOMNodeRemoved 事件,relatedNode 屬性等於 document.body。
2. 在 ul 上觸發 DOMNodeRemovedFromDocument 事件。
3. 在 ul 下的 每個 li 上 觸發DOMNodeRemovedFromDocument 事件。
4. 在 document.body 上觸發 DOMSubtreeModified 事件。
驗證代碼:
2. 插入節點
在使用appendChild,replaceChild 和 insertBefore 向DOM中插入節點的時候首先會觸發 DOMNodeInserted 事件。
首先觸發的是 DOMNodeInserted 事件,該事件的目標是被插入的節點,相同的 event.relatedNode 屬性中包含的是對父節點的引用。而且該事件是冒泡的。
其次爲在新插入的節點上觸發 DOMNodeInsertedIntoDocument 事件,該事件不冒泡。事件的目標爲被插入的節點,因此須要在該節點插入之給節點添加好事件處理程序。
4.7 HTML 5 事件
DOM規範沒有涵蓋全部的瀏覽器支持的事件許多瀏覽器推出了本身的特殊事件。HTML5詳盡的列出了瀏覽器應該支持的全部事件。
1. contextmenu 事件
爲了實現上下文菜單,windows下是鼠標右鍵單擊的菜單,如何操做該事件,因而就有了contextmenu 事件,用以表示什麼時候該顯示上下文菜單,以便開發人員自定義上下文菜單。
JS 實現自定義上下文菜單
基本瀏覽器均已支持。
2. beforeunload 事件
window對象上的事件處理函數, 是爲了讓開發人員有可能在頁面卸載以前來阻止該操做。
除了 opera11以前版本,其他均以支持。
3. DOMContentLoaded 事件
window的load事件會在頁面中的一切都加載完畢以後觸發,而DOMContentLoaded 事件則在完整的DOM數以後就觸發,不會受到圖片,JS文件,css文件等影響,意味着客戶能夠更早的與頁面交互。
支持的瀏覽器有 IE9+ FF Chrome SF Op9+ 。
對於不支持的瀏覽器建議頁面加載期間設置一個事件爲 0ms 的setTimeout 來進行模擬處理。即在當前JS處理完畢後當即運行該函數。
4. readystatechange 事件
IE 爲 DOM 文檔中的某些部分提供了 readystatechange 事件,目的是爲了提供與文檔或者元素的加載狀態相關的信息,支持readystatechange 的每一個對象還有一個 readyState 屬性:
1. uninitialized 未初始化 :對象存在可是還沒有初始化
2. loading 正在加載 : 對象正在加載數據
3. loaded 加載完畢 :對象加載數據完成
4. interactive 交互 : 能夠操做對象可是尚未徹底加載
5. complete 完成 : 對象已經加載完畢
狀態很直觀,可是並不是全部的對象都會經歷 readyState 的這些階段。
對於 document 來講, 值爲interactive 的readyState 會與DOMContentLoaded 大體相同,可是不能保證前後順序。
支持readystatechange的有 IE 、Firefox 4+ 與 Opera。
還有一個須要注意的是
咱們要檢測加載完畢的時候須要一併檢測 readyState的兩個狀態,而且在事件調用了一次以後便移除該事件。由於有些對象會值出現某一個狀態,而有些會出現兩個狀態。
5. pageshow 和 pagehide 事件
頁面顯示,卸載的時候觸發。有時當咱們使用頁面的前進後退按鈕,會調用頁面的緩存而不會觸發頁面的load,而 pageshow 則不會影響。其對象爲 window。而pagehide則與 beforeunload相似。
兼容的瀏覽器 Firefox,Safari 5+,chrome 和 opera。IE9及以前版本均爲支持。
6. hashchange
HTML5 新增的 hashchange 事件,再URL的參數列表(url中 #後部分)發生變化的時候觸發通知開發人員。主要用於在ajax應用中開發人員常常須要利用 url參數列表來保存狀態或者導航信息。固然也是須要將該事件處理程序添加給 window 對象。
event對象中會有兩個屬性 oldURL 和 newURL,保存了變化先後各自的URL。可使用如下代碼來檢測
var isSupported = ( "onhashchange" in window ) && ( document.documentMode === undefined || document.documentmode > 7 );
4.8 設備事件
設備事件 device event 可讓開發人員肯定用戶在怎樣的使用設備,W3C從2011年開始就在制定關於設備時間的新草案,以涵蓋不斷增加的設備類型而且定義相關事件。
1. orientationchange 事件
蘋果公司爲必定 safari 添加orientationchange 事件,方便開發人員對於橫向與豎向查看模式的處理。
window.orientation 屬性中包含3個值,0 表示肖像模式,90 表明左旋轉橫向模式 -90表明右旋轉橫向模式,文檔中還有 180 表明倒置,但還未支持。
只要設備更改了查看模式就會觸發 orientationchange 事件,event中不包含任何有價值的信息,惟一信息能夠經過 window.orientation 訪問到。
2. MozOrientation 事件
Firefox 3.6 爲檢測設備的方向引入了該事件。與iSO的 orientationchange 事件不一樣,該事件只能提供一個平面方向的變化。
event 對象中包含3個值, 想x,y,z處於 1 至 -1 之間,豎直狀態下 x:0 ,y:0, z:1若是設備向右傾斜,x 會減少,反之向左傾斜x增大。向遠離用戶方向傾斜 y減小,接近方向傾斜則會增大。z表示垂直上的加速度,1表示靜止不動,失重狀態下爲0 (爲實驗性的API)。
3. deviceorientation事件 與 devicemotion事件。
4.9 觸摸 與 手勢事件
touchstart : 當手指觸摸屏幕觸發,便是已經有手指放在屏幕上了也會觸發。
touchmove:在手指滑動時候連續觸發。
touchend:當手指從屏幕上移開的時候觸發。
touchcancel:當系統中止跟蹤觸摸時觸發。
以上的都可以冒泡以及取消。除了常見的DOM屬性以外,觸摸事件還包括3個用於跟蹤觸摸的屬性。
touches:表示當前跟蹤的觸摸操做Touch對象數組。
targetTouches:特定於時間目標的Touch對象數組。
changeTouches:上次觸摸以來發生改變了的Touch對象數組。
其中每一個 Touch 對象包含一下屬性。
clientX:觸摸目標在視口中的x座標。
clientY:觸摸目標在視口中的y座標。
identifier:標識觸摸的惟一id。
pageX:觸摸目標在頁面中的x座標。
pageY:觸摸目標在頁面中的y座標。
screenX:觸摸目標在屏幕中的x座標。
screenY:觸摸目標在屏幕中的y座標。
target:觸摸的DOM節點目標。
在觸摸屏幕上的元素時,事件觸發程序順序以下。
1. touchstart
2. mouseover
3. mousemove 一次
4. mousedown
5. mouseup
6. click
7. touchend
對於手勢事件
gesturestart:當一個手指已經在屏幕上,另一個手指觸摸屏幕的時候觸發。
gesturechange:當觸摸屏幕的任何一個手指位子發生變化的時候觸發。
gestureend:當任何一個手指從屏幕上移開的時候觸發。‘
5. 內存與性能
JS中添加到引入面上的事件處理程序數量將直接關係到頁面的總體運行性能,首先每一個函數都是對象會佔用內存,內存佔用越多性能就會越差,其次指定事件的處理程序致使的對DOM訪問次數會延遲整個頁面的交互就緒時間。
5.1 事件委託
對於 事件處理程序過多 的問題,採用的解決方案就是 事件委託。
事件委託利用冒泡,指定一個事件處理程序來管理某一類型的全部事件。
對於列表項點擊觸發事件,能夠逐一的對各項 li 進行事件處理程序的綁定,可是一旦 li 項較多的時候就會有很大的問題,事件委託就是將事件處理程序綁定在外層的 ul 上(也能夠是更外層的元素上),進行 event 中 target 判斷來執行代碼。
若是可行能夠考慮在document對象上添加一個處理程序,用以處理頁面上發生的某種特定類型事件。
1. document 對象很快就能夠訪問,能夠在頁面生命週期的任什麼時候間點添加處理程序甚至無需等待DOMContentloaded 或者 load 事件。
2. 頁面的設置事件處理程序所需時間更少。
3. 整個頁面佔用的內存空間更少,提高總體性能。
最適合採用的委託事件有 click,mousedown,mouseup,keydown,keyup和 keypress。
5.2 移除事件處理程序
每當將事件處理程序指定給元素的時候,運行中的瀏覽器代碼和支持頁面交互的JS之間就會創建一個鏈接,鏈接越多頁面就越慢在不須要的時候移除那些不須要的事件處理程序也能改善頁面總體性能。
第一種狀況須要注意的是,從文檔中移除帶有事件處理程序的元素時,可能經過純粹的DOM操做例如 removeChild 和 replaceChild 方法,但更多的是使用 innerHTML 來替換頁面中的某一部分,若是是使用 innerHTML來刪除了那麼原來的事件處理程序極有可能將沒法被當作垃圾回收。
還有一種狀況就是在卸載頁面的時候,對於IE8以及以前版本瀏覽器依舊有不少問題。在頁面卸載以前沒有清理乾淨事件處理程序,那麼他們將依舊滯留在內存之中。在咱們切換頁面以及刷新等操做的時候就會不斷地消耗內存。
6. 模擬事件
不多人知道可使用JS在任意時刻來觸發特定事件,而此時的事件如同瀏覽器建立事件同樣,在測試web應用程序的時候模擬出發時間是一種極其有用的技術。DOM2規範了此模擬事件的方式。IE9,Opera,Firefox,chrome和safari。
http://blog.chinaunix.net/uid-26672038-id-3956106.html