事件就是用戶或瀏覽器自身執行的某種動做,諸如 click、 load 等。而相應某個事件的函數就叫事件處理程序(或事件偵聽器),如 onclick、 onload 等。
javascript
事件捕獲,與"事件冒泡"相反,從"window"對象開始,沿着 DOM 樹逐級向下傳播,直到目標元素爲止。html
二者能夠用下圖表示:java
其實二者之間還有一個階段:處於目標的發生階段。
數組
添加和刪除事件均有兩種方法,均爲 Element 類型的對象的方法。如下的 "callback" 表示事件處理的回調函數,如function callback(event){ }
,"event" 爲內部提供的參數,表示事件對象。須要注意的是,DOM0 級與 DOM 2級 添加事件處理函數會被同時觸發,互不干擾。
瀏覽器
特色是帶有"on"字眼。這種方法添加的事件處理函數會在冒泡階段被處理。這兩個方法的優勢是使用簡單,直接賦值一個函數(或匿名函數或箭頭函數);缺點是隻能賦值一個函數,後賦值會覆蓋前者,因此刪除事件也會清除全部。下面以"onclick"爲例。
app
ele.onclick = callback
ele.onclick = null
這兩個方法的優勢是能對同一個元素依次添加多個事件處理函數,也能單獨移除某個事件處理函數(必須提供函數的對象),並且能針對冒泡或捕獲階段處理。eventType 表示事件的類型,如 "click" 等,是不帶"on"字的;isBubbles 是可選參數,默認爲 false ,表示在冒泡階段處理函數,true 則表示是否在捕獲階段處理函數。下面以"click"爲例。
ide
ele.addEventListener(eventType, callback, isCapture?)
ele.removeEventListener(eventType, callback, isCapture?)
瀏覽器會將 event 對象是傳入到事件處理程序中。event 對象有如下屬性/方法:函數
屬性/方法 | 類型 | 說明 |
---|---|---|
bubbles | Bool | 表示事件是否冒泡。 |
cancelable | Bool | 表示是否能夠取消事件的默認行爲。 |
currentTarget | Elem | 其事件處理程序當前正在處理事件的那個元素。 |
defaultPrevented | Bool | 爲 true 表示已經調用了 preventDefault()。 |
datail | Int | 與事件相關的細節信息。 |
eventPhase | Int | 調用事件程序的階段: 1-捕獲階段;2-"處於目標";3-冒泡階段。 |
target | Element | 事件的目標元素對象。 |
trusted | Bool | 爲 true 表示事件是瀏覽器生成的;不然爲開發人員經過 JavaScript 建立的。 |
type | Str | 被觸發的事件的類型。如, "click" 、 "mouseover" 等。 |
view | AbstractView | 與事件關聯的抽象視圖。等同於發生事件的 window 對象。 |
preventDefault() | Func | 取消事件的默認行爲。如,<a>標籤的單擊事件就是跳轉連接。( cancelable 必須爲 true ) |
stopImmediatePropagation() | Func | 取消事件的進一步捕獲或冒泡,同時阻止任何事件處理程序被調用。 |
stopPropagation() | Func | 取消事件的進一步捕獲或冒泡。 |
preventDefault()
方法。stopPropagation()
方法。document.addEventListener('load', callback)
。window.addEventListener('resize', callback)
。焦點事件會在頁面元素得到或失去焦點時觸發。默認狀況下,只有input等元素纔有焦點事件,但只要給<div>等元素添加tabindex
特性,一樣能觸發焦點事件,要注意的是,在得到焦點時,某些瀏覽器可能會爲該元素添加邊框等樣式。post
經過document.hasFocus()
能夠判斷用戶是否與該頁面互動(頁面未進行任何操做或不在屏幕內顯示則返回false)。
性能
經過document.activeElement
屬性能夠獲取當前被聚焦的元素。
鼠標事件繼承自 UI Event 。鼠標事件包括左鍵、右鍵、滾輪。單擊指代的是左鍵點擊一下,雙擊則左鍵連續點擊兩下。全部元素都支持鼠標事件。
除了mouseenter
和mouseleave
,全部鼠標事件都冒泡。
只有在同一個元素上相繼觸發mousedown
和mouseup
事件,纔會觸發click
事件;相似的,只有觸發兩次click
事件纔會觸發一次dblclick
事件。
事件列表以下:
e.preventDefault()
能夠阻止"上下文菜單"的打開,而後經過獲取鼠標位置,在指定位置顯示自制的"菜單"。也能夠用mousedown
代替。鼠標觸發的事件,其event
對象有幾個屬性是值得關注的:
屬性 | 值類型 | 使用場景 | 說明 |
---|---|---|---|
clientX | Integer | * |
觸發該事件時,鼠標光標相對於瀏覽器視口的X軸位置。 |
clientY | Integer | * |
觸發該事件時,鼠標光標相對於瀏覽器視口的Y軸位置。 |
pageX | Integer | 頁面有滾動條 | 觸發該事件時,鼠標光標相對於瀏覽器頁面(非視口)的X軸位置。 |
pageY | Integer | 頁面有滾動條 | 觸發該事件時,鼠標光標相對於瀏覽器頁面(非視口)的Y軸位置。 |
shiftKey | Boolean | 鍵盤組合鼠標 | 當按下"shift"鍵的同時觸發鼠標事件,該屬性值爲true,不然爲false。 |
ctrlKey | Boolean | 鍵盤組合鼠標 | 當按下"ctrl"鍵的同時觸發鼠標事件,該屬性值爲true,不然爲false。 |
altKey | Boolean | 鍵盤組合鼠標 | 當按下"alt"鍵的同時觸發鼠標事件,該屬性值爲true,不然爲false。 |
metaKey | Boolean | 鍵盤組合鼠標 | 當按下"meta"鍵的同時觸發鼠標事件,該屬性值爲true,不然爲false。 |
relatedTarget | Element | 與兩個元素有關的事件 | mouseover 、mouseout 、mouseleave 都與兩個元素有關,本屬性指向相關元素對象。 |
button | Integer | 觸發鼠標按鍵事件的按鍵 | 0:鼠標左鍵;1:鼠標滾輪按鈕;2:鼠標右鍵;3:鼠標"後退"鍵;4:鼠標"前進"鍵。 注意,click事件觸發的只會是 0 。 |
buttons | Integer | 獲取當前按下的多個鼠標按鍵 | 0:無任何按鍵;1:鼠標左鍵;2:鼠標滾輪按鈕;4:鼠標右鍵;8:鼠標"後退"鍵;16:鼠標"前進"鍵。 注意,多個按鍵之間用"加法"表示,如,同時按下左右鍵則爲 6 。 |
觸摸事件一樣繼承自 UI Event 。一般在移動端設備或能夠觸摸設備上使用該事件。上面提到的鼠標事件,如,click
、mousedown
、mouseup
,通常狀況下都能使用。觸摸事件都是會冒泡的。
這幾個觸摸事件對象除了繼承 UI Event 事件的屬性外,還包含以下屬性,都是 TouchList ,由 Touch 對象組成的類數組。每一個 touch 對象表示一個觸摸點,touch 對象保存着跟觸摸點相關的信息(如,id、位置信息、按壓力度等)。
當用戶按下鍵盤的按鍵就會觸發鍵盤事件。鍵盤的事件有 3 個:
keydown
、keypress
、keyup
都是同類型的事件對象。都含有相同的屬性,通常獲取用戶按下的按鍵再進行處理,詳細請查看MDN文檔。
還有複合事件(composition Event)是與鍵盤輸入有關的,其實就是咱們常說的輸入法。有三個複合事件:
這類事件對象中的data
屬性是值得關注的。compositionstart
只表示啓動了輸入法,data的值永遠爲空。compositionupdate
表示正在向輸入法輸入字符,每次更新都會觸發,以下圖,當正在輸入且未選擇字符時,data的值與文本框顯示的相同,即shu'ru'fa
;當選擇字符後,data值會更新爲選擇的字符,即輸入法
。compositionend
在關閉輸入法時觸發,因此data屬性的值就是留在輸入框內的值。
拖放事件是DragEvent
類型。用戶經過將指針設備(例如鼠標)放置在觸摸表面上而且而後將指針拖動到新位置(諸如另外一個DOM元素)來發起拖動。"拖放"實際是有兩部分:拖(drag)和放(drop)。文本和圖片是默承認以拖放的,而其餘的 DOM 元素能夠經過設置特性draggable="true"
達到能夠拖放。
有以下拖放事件:
drop
事件纔會觸發。能夠參考 MDN 文檔的一個拖放例子。簡單總結幾點:
draggable="true"
才能拖放。removeChild
、appendChild
等。event.target
的樣式設置,能夠加強拖放時給用戶的感覺。dragover
事件是drop
事件的前提,因此,不添加dragover
事件處理函數則沒法觸發drop
事件。drop
事件的默認行爲是打開連接,經過event.preventDefault()
能夠禁用其行爲。設備事件一般包含兩種:設備方向改變、設備被移動。一般用於手機和平板。都是window
對象上的事件。
事件對象的屬性中關於方向的 x
、y
、z
軸以下圖。事件對象的屬性中關於面的alpha
對應的xy組成的面;bata
對應的是yz組成的面;gamma
對應的是zx組成的面。
具體事件以下:
Event
對象。注意,設備設定了"鎖定旋轉"將不會觸發該事件。但事件對象自己並無太多可用信息,須要配合window.orientation
對象使用,用於獲取設備的方向,window.orientation
可能有三個值:0 表示"垂直模式",即設備底部指向地面;90 表示左轉的"橫屏模式",即設備的左側指向地面;-90 表示右轉的"橫屏模式",即設備的右側指向地面。DeviceOrientationEvent
對象。是一個實驗中的功能。DeviceMotionEvent
對象。是一個實驗中的功能。null
。null
。null
。如下未寫明的均爲Event
類型的事件。
window
對象上。window
或document
對象上。window
對象上。不冒泡。使用該事件須要兩個條件:鼠標焦點必須在該文檔上;event.returnValue
必須賦值。window.addEventListener('beforeunload', (e) => {
// 原意是顯示 returnValue 做爲提示內容,但實際並沒顯示
// 但賦值是必須的,能夠是任何值,不然不會觸發事件
e.returnValue = ''
})複製代碼
document.readyState
屬性發生改變,readystatechange
事件會被觸發。只能用在document
對象上。用途不大,通常咱們只關心加載完成的狀態,使用DOMContentLoaded
事件便可。oldURL
和newURL
。但仍是建議使用location
對象肯定當前地址的參數列表。是HashChangeEvent
類型的事件。window
。事件對象中的persisted
屬性值得關注,表示頁面是否保存在內存中或是否從內存中加載(要注意兩點:當頁面從內存中加載,load事件不會觸發;當設置了unload
事件,頁面不會保存在內存中)。是PageTransitionEvent
類型的事件。form.submit()
例外,不會觸發該事件。FocusEvent
類型的對象。FocusEvent
類型的對象。target
對象上的兩個屬性間接獲取:selectionStart
、selectionEnd
。例子:e.target.value.substring(e.target.selectionStart,e.target.selectionEnd)
。開發者能夠建立自定義事件,刻意觸發特定事件,在測試 Web 應用時極其有用。
建立Event
對象須要使用new
關鍵字:event = new Event(typeArg, eventInit?);
,其中,typeArg
表示自定義事件的名稱;eventInit
是可選參數,是一個對象,包含三個字段"bubbles"
、"cancelable"
、"composed"
中的任意多個。
// 建立一個 名爲look,支持冒泡,不能被取消的 事件
let ev = new Event("look", {"bubbles":true, "cancelable":false});複製代碼
每一個Element
對象都有一個dispatch(event)
方法,用於觸發開發者建立的模擬事件,前提是已經給該元素添加事件監聽函數,event
表示模擬事件對象。下面給出一個完成的例子:
<button id="btn1">按鈕1</button>複製代碼
// 建立模擬事件對象
let myEvent = new Event("eventName", {"bubbles":true, "cancelable":false});
// 獲取元素對象,並添加事件監聽
let btn = document.getElementById('btn1');
btn.addEventListener('eventName', e => console.log(e));
// 觸發"eventName"事件
btn.dispatchEvent(myEvent);
複製代碼
上面說起到的事件類型都可以做爲構造函數。如,要建立DeviceMotionEvent
類型的事件對象,則let ev = new DeviceMotionEvent('evnetName', {});
便可,其餘類型同理。
關於這部分,要說的只有兩點:列表中使用的事件綁定,建議使用事件委託,如<li>均不添加事件處理函數,只在外層的<ul>添加,經過target判斷是哪一個<li>再處理;刪除元素前,先把綁定的事件函數移除。
過多事件致使性能降低的緣由:每一個函數都是對象,都會佔用內存,對象越多性能越差;必須事先指定全部的事件處理函數而致使DOM訪問次數過多,會延遲整個頁面的交互就緒事件。