JavaScript事件說明

瀏覽器中的JavaScript使用事件驅動的編程模型。一切都始於事件。這是對JavaScript事件的介紹,以及事件處理的工作方式

介紹

瀏覽器中的JavaScript使用事件驅動的編程模型。

一切都始於事件。

該事件可能是DOM加載,完成獲取的異步請求,用戶單擊元素或滾動頁面或用戶在鍵盤上鍵入。

有很多不同類型的事件。

事件處理程序

您可以使用事件處理程序,這是事件發生時調用的函數。

您可以為同一事件註冊多個處理程序,並且在該事件發生時將全部調用它們。

JavaScript提供了三種註冊事件處理程序的方式:

內聯事件處理程序

由於其約束,今天很少使用這種事件處理程序樣式,但這是JavaScript早期的唯一方法:

<a href="site.com" onclick="dosomething();">A link</a>

DOM事件處理程序

當一個對象最多具有一個事件處理程序時,這很常見,因為在這種情況下無法添加多個處理程序:

window.onload = () => {
  //window loaded
}

在處理時最常用XHR要求:

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
  //.. do something
}

您可以使用以下方法檢查處理程序是否已分配給屬性if ('onsomething' in window) {}

使用addEventListener()

這是現代方式。此方法允許註冊所需數量的處理程序,並且它是最受歡迎的處理程序:

window.addEventListener('load', () => {
  //window loaded
})

請注意,IE8和更低版本不支持此功能,而是使用了它自己的attachEvent()API。如果您需要支持較舊的瀏覽器,請記住這一點。

聆聽不同的元素

你可以聽window攔截“全局”事件(例如鍵盤的用法),您可以偵聽特定元素以檢查事件的發生,例如鼠標單擊按鈕。

這就是為什麼addEventListener有時會被調用window,有時在DOM元素上。

事件對象

一個事件處理程序得到一個Event對像作為第一個參數:

const link = document.getElementById('my-link')
link.addEventListener('click', event => {
  // link clicked
})

該對象包含許多有用的屬性和方法,例如:

  • target,是引發事件的DOM元素
  • type,事件類型
  • stopPropagation(),稱為停止在DOM中傳播事件

查看完整清單)。

其他屬性由特定類型的事件提供,例如Event是用於不同特定事件的接口:

每個頁面都有一個鏈接的MDN頁面,因此您可以檢查它們的所有屬性。

例如,當發生KeyboardEvent時,您可以以可讀格式檢查按下了哪個鍵(EscapeEnter依此類推)key財產:

window.addEventListener('keydown', event => {
  // key pressed
  console.log(event.key)
})

在發生鼠標事件時,我們可以檢查按下了哪個鼠標按鈕:

const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
  // mouse button pressed
  console.log(event.button) //0=left, 2=right
})

事件冒泡和事件捕獲

冒泡和捕獲是事件用於傳播的兩個模型。

假設您的DOM結構是

<div id="container">
  <button>Click me</button>
</div>

您想跟踪用戶何時單擊按鈕,並且有2個事件偵聽器,其中一個button和一個#container。請記住,單擊子元素將始終傳播到其父元素,除非您停止傳播(請參閱下文)。

這些事件偵聽器將按順序調用,此順序由所使用的事件冒泡/捕獲模型確定。

起泡表示事件從被單擊的項(子項)一直傳播到其所有父樹,從最近的樹開始。

在我們的示例中,button會在#container處理程序。

捕捉相反:外部事件處理程序在更具體的處理程序之前觸發,button

默認情況下,所有事件都會冒泡

您可以通過將第三個參數應用於addEventListener並將其設置為來選擇採用事件捕獲true

document.getElementById('container').addEventListener(
  'click',
  () => {
    //window loaded
  },
  true
)

注意首先運行所有捕獲事件處理程序

然後是所有冒泡事件處理程序。

順序遵循此原則:DOM從Window對像開始遍歷所有元素,然後查找被單擊的項目。這樣做時,它將調用與事件關聯的任何事件處理程序(捕獲階段)。

一旦到達目標,它將重複直到父級樹的旅程,直到Window對象,再次調用事件處理程序(冒泡階段)。

停止傳播

除非停止,否則DOM元素上的事件將傳播到其所有父元素樹。

<html>
  <body>
    <section>
      <a id="my-link" ...>

的點擊事件a將傳播到section接著body

您可以通過調用stopPropagation()Event的方法,通常在事件處理程序的末尾:

const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
  // process the event
  // ...

  event.stopPropagation()
})

以下是您可能會處理的最常見事件的列表。

加載

load被開除windowbody頁面加載完成後的元素。

鼠標事件

click單擊鼠標按鈕時觸發。dblclick兩次單擊鼠標時。當然在這種情況下click在此事件之前被解僱。mousedownmousemovemouseup可以組合使用以跟踪拖放事件。小心mousemove,因為它在鼠標移動過程中會多次觸發(請參見節流之後)

鍵盤事件

keydown按下鍵盤按鈕時觸發(以及在按鈕按下時重複按鍵的任何時間)停留按下)。keyup釋放鍵時觸發。

滾動

scroll事件被觸發window每次滾動頁面。在事件處理程序內,您可以通過檢查以下內容來檢查當前滾動位置window.scrollY

請記住,此事件不是一次性事件。它在滾動過程中會觸發很多次,而不僅僅是在滾動結束或開始時,所以不要在處理程序中進行任何繁重的計算或操作-使用節流反而。

節流

如上所述,mousemovescroll有兩個事件不會在每個事件中一次性觸發,而是在動作的所有持續時間內連續調用它們的事件處理函數。

這是因為它們提供了坐標,因此您可以跟踪正在發生的事情。

如果在事件處理程序中執行複雜的操作,則會影響性能並給站點用戶帶來緩慢的體驗。

提供節流功能的庫洛達什用100多行代碼實施它,以處理所有可能的用例。這是一個簡單易懂的實現,它使用setTimeout每100毫秒緩存一次滾動事件:

let cached = null
window.addEventListener('scroll', event => {
  if (!cached) {
    setTimeout(() => {
      //you can access the original event at `cached`
      cached = null
    }, 100)
  }
  cached = event
})

免費下載我的JavaScript初學者手冊


更多js教程: