(JS基礎)事件

基本概念

定義

事件就是用戶或瀏覽器自身執行的某種動做,諸如 click、 load 等。而相應某個事件的函數就叫事件處理程序(或事件偵聽器),如 onclick、 onload 等。
javascript

事件捕獲 與 事件冒泡

事件冒泡,是指事件開始的時候由 最具體的元素(文檔中嵌套層次最深的那個點)接受,而後 沿着 DOM 樹逐級向上傳播,直到 "window" 對象爲止

事件捕獲,與"事件冒泡"相反,從"window"對象開始,沿着 DOM 樹逐級向下傳播,直到目標元素爲止html

二者能夠用下圖表示:java

其實二者之間還有一個階段:處於目標的發生階段
數組


添加和刪除事件

添加和刪除事件均有兩種方法,均爲 Element 類型的對象的方法。如下的 "callback" 表示事件處理的回調函數,如function callback(event){ },"event" 爲內部提供的參數,表示事件對象。須要注意的是,DOM0 級與 DOM 2級 添加事件處理函數會被同時觸發,互不干擾
瀏覽器

DOM0 級

特色是帶有"on"字眼。這種方法添加的事件處理函數會在冒泡階段被處理。這兩個方法的優勢是使用簡單,直接賦值一個函數(或匿名函數或箭頭函數);缺點是隻能賦值一個函數,後賦值會覆蓋前者,因此刪除事件也會清除全部。下面以"onclick"爲例。
app

  • 添加:ele.onclick = callback
  • 刪除:ele.onclick = null

DOM2 級

這兩個方法的優勢是能對同一個元素依次添加多個事件處理函數,也能單獨移除某個事件處理函數(必須提供函數的對象),並且能針對冒泡或捕獲階段處理eventType 表示事件的類型,如 "click" 等,是不帶"on"字的;isBubbles可選參數,默認爲 false ,表示在冒泡階段處理函數,true 則表示是否在捕獲階段處理函數。下面以"click"爲例。
ide

  • 添加:ele.addEventListener(eventType, callback, isCapture?)
  • 刪除:ele.removeEventListener(eventType, callback, isCapture?)

event 對象

瀏覽器會將 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 取消事件的進一步捕獲或冒泡

下面再說說某些 經常使用的屬性
    1.  currentTarget 指向的是函數正在處理的元素對象,與處理程序內部的 "this" 對象相等。非"目標階段"時, currentTarget 指向的就是冒泡或捕獲通過的對象;"目標階段"時currentTarget 與 target 對象相同
    2. type 對象經常使用於一個函數處理多個事件。經過判斷 type 的值區別處理。
    3. 取消元素的默認行爲,請使用preventDefault()方法。
    4. 取消事件的冒泡或捕獲,請使用stopPropagation()方法。
    5. event 對象只存在於處理程序執行期間。

事件類型

UI 事件(UIEvent)

UI 事件是指,與用戶操做不必定有關的事件。
  • load:當元素/對象徹底加載後(包括全部的圖像、JavaScript文件、CSS文件等外部資源)觸發。除了window、document、<body>以外,全部能引用外部資源的元素都能使用本事件,如<object>、<img>等。建議在 document 上添加事件判斷 HTML 頁面是否徹底加載完成,如document.addEventListener('load', callback)
  • unload:與 load 事件相對應,在文檔被徹底卸載後觸發。
  • abort:加載外部資源期間終止下載時觸發。
  • error:JavaScript 錯誤、沒法加載外部資源、沒法嵌入內容時都會觸發。
  • select:當用戶選擇文本框(<input>或<textarea>)中的字符時觸發
  • resize當瀏覽器窗口的寬高被調整時觸發。建議在 window 對象上添加該事件,即window.addEventListener('resize', callback)
  • scroll:具備滾動條的元素滾動時觸發

焦點事件(FocusEvent)

焦點事件會在頁面元素得到或失去焦點時觸發。默認狀況下,只有input等元素纔有焦點事件,但只要給<div>等元素添加tabindex特性,一樣能觸發焦點事件,要注意的是,在得到焦點時,某些瀏覽器可能會爲該元素添加邊框等樣式。post

經過document.hasFocus()能夠判斷用戶是否與該頁面互動(頁面未進行任何操做或不在屏幕內顯示則返回false)。
性能

經過document.activeElement屬性能夠獲取當前被聚焦的元素

如下是焦點事件:
  • blur:在元素失去焦點時觸發不會冒泡
  • focus:在元素得到焦點時觸發不會冒泡

鼠標事件(MouseEvent)

鼠標事件繼承自 UI Event 。鼠標事件包括左鍵、右鍵、滾輪。單擊指代的是左鍵點擊一下,雙擊則左鍵連續點擊兩下。全部元素都支持鼠標事件。

除了mouseentermouseleave,全部鼠標事件都冒泡

只有在同一個元素上相繼觸發mousedownmouseup事件纔會觸發click事件;相似的,只有觸發兩次click事件纔會觸發一次dblclick事件

事件列表以下:

  • click鼠標單擊時觸發,最爲經常使用的一個事件。
  • dblclick鼠標雙擊時觸發。移動端不支持,且雙擊只會放大頁面。
  • mousedown按下鼠標任意鍵時觸發。
  • mouseup釋放鼠標按鍵時觸發。
  • mouseenter:鼠標光標從元素外部移動到元素範圍內時觸發。
  • mouseleave:鼠標光標從元素內部移動到元素範圍外時觸發。
  • mousemove:鼠標光標在元素內部移動重複觸發
  • mouseout:鼠標光標從事件元素移動到另外一個元素(包括子元素)時觸發。
  • mouseover:鼠標光標從事件元素的外部移動到事件元素的內部時觸發。
  • contextmenu右擊鼠標或移動端長按時觸發的事件,默認行爲是打開"上下文菜單"經過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 與兩個元素有關的事件 mouseovermouseoutmouseleave都與兩個元素有關,本屬性指向相關元素對象。
button Integer 觸發鼠標按鍵事件的按鍵 0:鼠標左鍵;1:鼠標滾輪按鈕;2:鼠標右鍵;3:鼠標"後退"鍵;4:鼠標"前進"鍵。
注意,click事件觸發的只會是 0 。
buttons Integer 獲取當前按下的多個鼠標按鍵 0:無任何按鍵;1:鼠標左鍵;2:鼠標滾輪按鈕;4:鼠標右鍵;8:鼠標"後退"鍵;16:鼠標"前進"鍵。
注意,多個按鍵之間用"加法"表示,如,同時按下左右鍵則爲 6 。

觸摸事件(TouchEvent)

觸摸事件一樣繼承自 UI Event 。一般在移動端設備或能夠觸摸設備上使用該事件。上面提到的鼠標事件,如,clickmousedownmouseup,通常狀況下都能使用。觸摸事件都是會冒泡的。

  • touchstart:當手指觸摸屏幕時觸發;即便已經有手指在屏幕上。
  • touchmove:當手指在屏幕上滑動連續觸發
  • touchend:當手指從屏幕上移開時觸發。
  • touchcancel:當觸點因爲某些緣由被中斷時觸發。例如,彈窗打斷;觸點離開文檔窗口進入瀏覽器界面元素;產生的觸摸點超過了設備所支持的。

這幾個觸摸事件對象除了繼承 UI Event 事件的屬性外,還包含以下屬性都是 TouchList ,由 Touch 對象組成的類數組。每一個 touch 對象表示一個觸摸點,touch 對象保存着跟觸摸點相關的信息(如,id、位置信息、按壓力度等)。

    • touches:當前屏幕上全部觸摸點的列表,即便某些觸摸點不在事件觸發對象上
    • targetTouches:當前對象上全部觸摸點的列表。
    • changeTouches:表示自上次觸摸以來發生變化的觸摸點列表,簡單說就是,當新增的觸摸點時,本屬性則包含新增的觸摸點;當減小觸摸點時,本屬性則包含減小的觸摸點;而前兩個屬性只獲取當前存在的觸摸點。

鍵盤事件(KeyboardEvent)

當用戶按下鍵盤的按鍵就會觸發鍵盤事件。鍵盤的事件有 3 個:

  • keydown:當用戶按下鍵盤上的任意按鍵時觸發。按住不放會重複觸發
  • keypress:當用戶按下鍵盤上的字符(即不包括 F*、功能鍵等)按鍵時觸發。按住不放會重複觸發
  • keyup:當用戶釋放鍵盤按鍵時觸發。
  • textInput僅在文本框輸入時觸發。能夠對用戶輸入的內容獲取。

keydownkeypresskeyup都是同類型的事件對象。都含有相同的屬性,通常獲取用戶按下的按鍵再進行處理,詳細請查看MDN文檔

還有複合事件(composition Event)是與鍵盤輸入有關的,其實就是咱們常說的輸入法。有三個複合事件:

這類事件對象中的data屬性是值得關注的。compositionstart只表示啓動了輸入法,data的值永遠爲空。compositionupdate表示正在向輸入法輸入字符,每次更新都會觸發,以下圖,當正在輸入且未選擇字符時,data的值與文本框顯示的相同,即shu'ru'fa;當選擇字符後,data值會更新爲選擇的字符,即輸入法compositionend在關閉輸入法時觸發,因此data屬性的值就是留在輸入框內的值。

拖放事件(DragEvent)

拖放事件是DragEvent類型。用戶經過將指針設備(例如鼠標)放置在觸摸表面上而且而後將指針拖動到新位置(諸如另外一個DOM元素)來發起拖動。"拖放"實際是有兩部分:拖(drag)放(drop)。文本和圖片是默承認以拖放的,而其餘的 DOM 元素能夠經過設置特性draggable="true"達到能夠拖放

有以下拖放事件:

  • drag:當拖動元素或選擇文本時觸發。
  • dragstart:當用戶開始拖動元素或選擇文本時觸發。
  • dragend:當拖動操做結束時(釋放鼠標按鈕或按下退出鍵)觸發。
  • dragenter:當拖動的元素或選擇文本進入有效的放置目標時觸發。
  • dragleave: 當拖動的元素或文本選擇離開有效的放置目標時觸發。
  • dragexit:當元素再也不是拖動操做的選擇目標時觸發。
  • dragover:當將元素或文本選擇拖動到有效放置目標(每幾百毫秒)時觸發。注意,必須先添加此事件的處理函數,drop事件纔會觸發
  • drop:當在有效放置目標上放置元素或選擇文本時觸發。

能夠參考 MDN 文檔的一個拖放例子。簡單總結幾點

  1. 非文本或圖片的元素,必須添加特性draggable="true"才能拖放。
  2. 拖放元素的實現依賴於節點的刪除和添加方法,如removeChildappendChild等。
  3. 經過event.target的樣式設置,能夠加強拖放時給用戶的感覺。
  4. dragover事件是drop事件的前提,因此,不添加dragover事件處理函數則沒法觸發drop事件。
  5. drop事件的默認行爲是打開連接,經過event.preventDefault()能夠禁用其行爲。

設備事件

設備事件一般包含兩種:設備方向改變、設備被移動。一般用於手機和平板。都是window對象上的事件。

事件對象的屬性中關於方向的 xyz 軸以下圖。事件對象的屬性中關於面的alpha對應的xy組成的面;bata對應的是yz組成的面;gamma對應的是zx組成的面。


具體事件以下:

  • orientationchange:當設備向左或向右旋轉時觸發。事件對象是Event對象。注意,設備設定了"鎖定旋轉"將不會觸發該事件。但事件對象自己並無太多可用信息,須要配合window.orientation對象使用,用於獲取設備的方向,window.orientation可能有三個值:0 表示"垂直模式",即設備底部指向地面;90 表示左轉的"橫屏模式",即設備的左側指向地面;-90 表示右轉的"橫屏模式",即設備的右側指向地面。
  • deviceorientation:當設備在空間上移動時觸發,頁面顯示時(最小化後顯示;切換標籤後顯示)也會觸發。(蘋果設備不能觸發該事件)。事件對象是DeviceOrientationEvent對象。是一個實驗中的功能。
    • alpha:圍繞 z 軸旋轉時,y 軸的角度差;是一個 0~360 的浮點數。
    • beta:圍繞 y 軸旋轉時,z 軸的角度差;是一個 -180~180 的浮點數。
    • gamma:圍繞 x 軸旋轉時,z 軸的角度差;是一個 -90~90 的浮點數。
    • absolute:布爾值,表示設備返回的是否爲一個絕對值
    • compassCalibrated:布爾值,表示設備的指南針是否校準過
  • devicemotion:當設備在空間上受到的加速度時觸發(包括重力)。即該事件會不斷觸發。事件對象是DeviceMotionEvent對象。是一個實驗中的功能。
    • acceleration:包含 x、y、z 屬性的對象,每一個方向上的加速度(不考慮重力)。讀取不到爲null
    • accelerationIncludingGravity:包含 x、y、z 屬性的對象,每一個方向上的加速度(考慮重力)。讀取不到爲null
    • interval:獲取事件觸發的間隔時間,毫秒爲單位。
    • rotationRate:包含表示面 alpha、beta、gamma 受力的屬性的對象。讀取不到爲null

其餘事件

如下未寫明的均爲Event類型的事件。

  • load:當文檔全部資源(包括連接外部資源)加載完成後觸發。必須添加到window對象上。
  • DOMContentLoaded:在造成完整的 DOM 樹後就會觸發。能夠添加到windowdocument對象上。
  • beforeunload:當頁面卸載前彈窗讓用戶確認關閉。必須添加到window對象上。不冒泡。使用該事件須要兩個條件:鼠標焦點必須在該文檔上;event.returnValue必須賦值。
    • window.addEventListener('beforeunload', (e) => {
        // 原意是顯示 returnValue 做爲提示內容,但實際並沒顯示
        // 但賦值是必須的,能夠是任何值,不然不會觸發事件
        e.returnValue = ''
      })複製代碼
  • readystatechange:當document.readyState屬性發生改變,readystatechange事件會被觸發。只能用在document對象上。用途不大,通常咱們只關心加載完成的狀態,使用DOMContentLoaded事件便可。
  • hashchange:當 URL 的參數列表(及 URL 中 "#" 號後面的全部字符串)發生變化時觸發。有兩個屬性:oldURLnewURL。但仍是建議使用location對象肯定當前地址的參數列表。是HashChangeEvent類型的事件。
  • pageshow 和 pagehide:當網頁在加載完成或卸載後會觸發頁面傳輸事件。並不經常使用,事件對象必須是window。事件對象中的persisted屬性值得關注,表示頁面是否保存在內存中或是否從內存中加載(要注意兩點:當頁面從內存中加載,load事件不會觸發;當設置了unload事件,頁面不會保存在內存中)。是PageTransitionEvent類型的事件。
  • submit:當表單提交時觸發。但form.submit()例外,不會觸發該事件。
  • reset:當表單重置時觸發。
  • focus:當元素得到焦點時觸發。是FocusEvent類型的對象。
  • blur:當元素失去焦點時觸發。是FocusEvent類型的對象。
  • change:當表單控件元素的值發生變化時觸發。(更多關於表單介紹
  • select:在文本框中選擇了文本時(鼠標釋放時)觸發。但方法內不包含已選擇文本的信息,須要經過target對象上的兩個屬性間接獲取:selectionStartselectionEnd。例子: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);
複製代碼

by the way

上面說起到的事件類型都可以做爲構造函數。如,要建立DeviceMotionEvent類型的事件對象,則let ev = new DeviceMotionEvent('evnetName', {});便可,其餘類型同理。


內存和性能

關於這部分,要說的只有兩點:列表中使用的事件綁定,建議使用事件委託,如<li>均不添加事件處理函數,只在外層的<ul>添加,經過target判斷是哪一個<li>再處理;刪除元素前,先把綁定的事件函數移除

過多事件致使性能降低的緣由:每一個函數都是對象,都會佔用內存,對象越多性能越差;必須事先指定全部的事件處理函數而致使DOM訪問次數過多,會延遲整個頁面的交互就緒事件。

相關文章
相關標籤/搜索