DOM 事件

事件被觸發以通知程式碼可能影響程式碼執行的“有趣變化”。這些變化可能來自使用者互動,例如使用滑鼠或調整視窗大小,底層環境狀態的變化(例如,低電量或來自作業系統的媒體事件),以及其他原因。

每個事件都由一個基於Event介面的物件表示,並且可能具有額外的自定義欄位和/或函式以提供有關發生事件的資訊。每個事件的文件都有一個表格(靠近頂部),其中包含指向關聯事件介面的連結以及其他相關資訊。不同事件型別的完整列表在Event > 基於 Event 的介面中給出。

本主題提供了一個索引,列出了您可能感興趣的主要型別事件(動畫、剪貼簿、Worker 等),以及實現這些事件的主要類。

事件索引

事件型別 描述 文件
Animation

Web Animation API相關的事件。

用於響應動畫狀態的變化(例如,當動畫開始或結束時)。

DocumentWindowHTMLElement上觸發的動畫事件。
非同步資料獲取

與資料獲取相關的事件。

AbortSignalXMLHttpRequestFileReader上觸發的事件。
Clipboard

Clipboard API相關的事件。

用於在內容被剪下、複製或貼上時發出通知。

DocumentElementWindow上觸發的事件。
組合

與組合相關的事件;“間接”輸入文字(而不是使用常規鍵盤按鍵)。

例如,透過語音轉文字引擎輸入的文字,或者使用特殊的組合鍵修改鍵盤按鍵以表示其他語言中的新字元。

Element上觸發的事件。
CSS 過渡

CSS 過渡相關的事件。

在 CSS 過渡開始、停止、取消等時提供通知事件。

DocumentHTMLElementWindow上觸發的事件。
資料庫

與資料庫操作相關的事件:開啟、關閉、事務、錯誤等。

IDBDatabaseIDBOpenDBRequestIDBRequestIDBTransaction上觸發的事件。
DOM 變動

與文件物件模型 (DOM) 層次結構和節點修改相關的事件。

警告:變動事件已棄用。應改用變動觀察器

拖放,滾輪

與使用HTML 拖放 API滾輪事件相關的事件。

拖放和滾輪事件源自滑鼠事件。雖然它們在使用滑鼠滾輪或拖放時觸發,但也可以與其他適當的硬體一起使用。

Document上觸發的拖放事件

Element上觸發的滾輪事件

焦點

與元素獲得和失去焦點相關的事件。

ElementWindow上觸發的事件。
表單

與表單的構建、重置和提交相關的事件。

HTMLFormElement上觸發的事件。
全屏

Fullscreen API相關的事件。

用於在全屏和視窗模式之間切換時以及在此轉換過程中發生錯誤時發出通知。

DocumentElement上觸發的事件。
Gamepad

Gamepad API相關的事件。

Window上觸發的事件。
手勢

建議使用觸控事件來實現手勢。

DocumentElement上觸發的事件。

此外,還有一些非標準手勢事件

History

History API相關的事件。

Window上觸發的事件。
HTML 元素內容顯示管理

與顯示或文字元素狀態變化相關的事件。

HTMLDetailsElementHTMLDialogElementHTMLSlotElement上觸發的事件。
輸入

與 HTML 輸入元素相關的事件,例如<input><select><textarea>

HTMLElementHTMLInputElement上觸發的事件。
鍵盤

與使用鍵盤相關的事件。

用於在按鍵抬起、按下或僅僅被按下時發出通知。

DocumentElement上觸發的事件。
文件載入/解除安裝

與文件載入和解除安裝相關的事件。

DocumentWindow上觸發的事件。

清單

漸進式 Web 應用清單安裝相關的事件。

Window上觸發的事件。
媒體

與媒體使用相關的事件(包括Media Capture and Streams APIWeb Audio API畫中畫 API等)。

ScriptProcessorNodeHTMLMediaElementAudioTrackListAudioScheduledSourceNodeMediaRecorderMediaStreamMediaStreamTrackVideoTrackListHTMLTrackElementOfflineAudioContextTextTrackTextTrackListElement/audioElement/video上觸發的事件。
訊息

與視窗從另一個瀏覽上下文接收訊息相關的事件。

Window上觸發的事件。
滑鼠

與使用計算機滑鼠相關的事件。

用於在滑鼠單擊、雙擊、上下事件、右鍵單擊、移入和移出元素、文字選擇等時發出通知。

指標事件提供了一種與硬體無關的滑鼠事件替代方案。拖放和滾輪事件源自滑鼠事件。

Element上觸發的滑鼠事件
網路/連線

與獲得和失去網路連線相關的事件。

Window上觸發的事件。

NetworkInformationNetwork Information API)上觸發的事件。

支付

Payment Request API相關的事件。

PaymentRequestPaymentResponse上觸發的事件。

效能

與任何分組到效能 API中的效能相關規範相關的事件。

Performance上觸發的事件。

指標

Pointer Events API相關的事件。

提供來自指向裝置(包括滑鼠、觸控、筆/手寫筆)的硬體無關通知。

DocumentHTMLElement上觸發的事件。
列印

與列印相關的事件。

Window上觸發的事件。
Promise 拒絕

當任何 JavaScript promise 被拒絕時,傳送到全域性指令碼上下文的事件。

Window上觸發的事件。
套接字

WebSockets API相關的事件。

WebSocket上觸發的事件。
SVG

與 SVG 影像相關的事件。

SVGElementSVGAnimationElementSVGGraphicsElement上觸發的事件。

文字選擇

Selection API中與文字選擇相關的事件。

HTMLTextAreaElementHTMLInputElement上觸發的事件 (selectionchange)。

Touch

Touch Events API相關的事件。

提供與觸控敏感螢幕互動(即使用手指或手寫筆)的通知事件。與Force Touch API無關。

DocumentElement上觸發的事件。
虛擬現實

WebXR Device API相關的事件。

警告:WebVR API(以及相關的Window事件)已棄用。

XRSystemXRSessionXRReferenceSpace上觸發的事件。
RTC(即時通訊)

WebRTC API相關的事件。

RTCDataChannelRTCDTMFSenderRTCIceTransportRTCPeerConnection上觸發的事件。
伺服器傳送事件

伺服器傳送事件 API相關的事件。

EventSource上觸發的事件。
語音

Web Speech API相關的事件。

SpeechSynthesisUtterance上觸發的事件。
Worker

Web Workers APIService Worker APIBroadcast Channel APIChannel Messaging API相關的事件。

用於響應新訊息和訊息傳送錯誤。Service worker 還可以接收其他事件通知,包括推送通知、使用者點選顯示的通知、推送訂閱失效、內容索引中專案刪除等。

ServiceWorkerGlobalScopeDedicatedWorkerGlobalScopeSharedWorkerGlobalScopeWorkerGlobalScopeWorkerBroadcastChannelMessagePort上觸發的事件。

建立和分派事件

除了內建介面觸發的事件之外,您還可以自己建立和分派 DOM 事件。此類事件通常被稱為合成事件,與瀏覽器觸發的事件相對。

建立自定義事件

事件可以使用Event建構函式建立,如下所示

js
const event = new Event("build");

// Listen for the event.
elem.addEventListener("build", (e) => {
  /* … */
});

// Dispatch the event.
elem.dispatchEvent(event);

此程式碼示例使用了EventTarget.dispatchEvent()方法。

新增自定義資料 – CustomEvent()

要向事件物件新增更多資料,存在CustomEvent介面,並且可以使用detail屬性傳遞自定義資料。例如,事件可以按如下方式建立

js
const event = new CustomEvent("build", { detail: elem.dataset.time });

這將允許您在事件監聽器中訪問附加資料

js
function eventHandler(e) {
  console.log(`The time is: ${e.detail}`);
}

新增自定義資料 – 繼承 Event

Event介面也可以被子類化。這對於重用、更復雜的自定義資料,甚至向事件新增方法都特別有用。

js
class BuildEvent extends Event {
  #buildTime;

  constructor(buildTime) {
    super("build");
    this.#buildTime = buildTime;
  }

  get buildTime() {
    return this.#buildTime;
  }
}

此程式碼示例定義了一個具有隻讀屬性和固定事件型別的BuildEvent類。

事件可以按如下方式建立

js
const event = new BuildEvent(elem.dataset.time);

然後可以使用自定義屬性在事件監聽器中訪問附加資料

js
function eventHandler(e) {
  console.log(`The time is: ${e.buildTime}`);
}

事件冒泡

通常希望從子元素觸發事件並由祖先元素捕獲它;可選地,您可以將資料包含在事件中

html
<form>
  <textarea></textarea>
</form>
js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

// Create a new event, allow bubbling, and provide any data you want to pass to the "detail" property
const eventAwesome = new CustomEvent("awesome", {
  bubbles: true,
  detail: { text: () => textarea.value },
});

// The form element listens for the custom "awesome" event and then consoles the output of the passed text() method
form.addEventListener("awesome", (e) => console.log(e.detail.text()));

// As the user types, the textarea inside the form dispatches/triggers the event to fire, using itself as the starting point
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));

動態建立和分派事件

元素可以監聽尚未建立的事件

html
<form>
  <textarea></textarea>
</form>
js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

form.addEventListener("awesome", (e) => console.log(e.detail.text()));

textarea.addEventListener("input", function () {
  // Create and dispatch/trigger an event on the fly
  // Note: Optionally, we've also leveraged the "function expression" (instead of the "arrow function expression") so "this" will represent the element
  this.dispatchEvent(
    new CustomEvent("awesome", {
      bubbles: true,
      detail: { text: () => textarea.value },
    }),
  );
});

觸發內建事件

此示例演示了使用 DOM 方法模擬複選框上的點選(即以程式設計方式生成點選事件)。檢視實際示例。

js
function simulateClick() {
  const event = new MouseEvent("click", {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  const cb = document.getElementById("checkbox");
  const cancelled = !cb.dispatchEvent(event);

  if (cancelled) {
    // A handler called preventDefault.
    alert("cancelled");
  } else {
    // None of the handlers called preventDefault.
    alert("not cancelled");
  }
}

註冊事件處理程式

有兩種推薦的註冊處理程式的方法。事件處理程式程式碼可以在事件觸發時執行,方法是將其分配給目標元素相應的onevent屬性,或者使用addEventListener()方法將處理程式註冊為元素的監聽器。在任何一種情況下,處理程式都將接收一個符合Event介面(或派生介面)的物件。主要區別在於可以使用事件監聽器方法新增(或刪除)多個事件處理程式。

警告:不建議使用 HTML onevent 屬性設定事件處理程式的第三種方法!它們會使標記膨脹,降低可讀性並使其更難除錯。有關更多資訊,請參閱內聯事件處理程式

使用 onevent 屬性

按照約定,觸發事件的 JavaScript 物件具有相應的“onevent”屬性(透過在事件名稱前加上“on”來命名)。這些屬性在事件觸發時被呼叫以執行關聯的處理程式程式碼,也可以由您自己的程式碼直接呼叫。

要設定事件處理程式程式碼,只需將其分配給適當的 onevent 屬性即可。每個元素中的每個事件只能分配一個事件處理程式。如果需要,可以透過將另一個函式分配給同一屬性來替換處理程式。

以下示例演示瞭如何使用onclick屬性為click事件設定greet()函式。

js
const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.onclick = greet;

請注意,表示事件的物件作為第一個引數傳遞給事件處理程式。此事件物件實現或派生自Event介面。

EventTarget.addEventListener

在元素上設定事件處理程式最靈活的方法是使用EventTarget.addEventListener方法。這種方法允許為元素分配多個監聽器,並允許在需要時使用EventTarget.removeEventListener移除監聽器。

注意:新增和移除事件處理程式的能力允許您,例如,讓同一個按鈕在不同情況下執行不同的操作。此外,在更復雜的程式中,清理舊的/未使用的事件處理程式可以提高效率。

以下示例演示瞭如何將greet()函式設定為click事件的監聽器/事件處理程式(如果需要,您可以使用匿名函式表示式而不是命名函式)。再次注意,事件作為第一個引數傳遞給事件處理程式。

js
const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.addEventListener("click", greet);

該方法還可以接受附加引數/選項來控制事件捕獲和移除的方面。更多資訊可以在EventTarget.addEventListener參考頁面上找到。

使用 AbortSignal

一個值得注意的事件監聽器功能是能夠使用中止訊號同時清理多個事件處理程式。

這是透過將相同的AbortSignal傳遞給所有希望一起移除的事件處理程式的addEventListener()呼叫來完成的。然後,您可以在擁有AbortSignal的控制器上呼叫abort(),它將移除所有使用該訊號新增的事件處理程式。例如,要新增一個我們可以使用AbortSignal移除的事件處理程式

js
const controller = new AbortController();

btn.addEventListener(
  "click",
  (event) => {
    console.log("greet:", event);
  },
  { signal: controller.signal },
); // pass an AbortSignal to this handler

然後可以這樣移除此事件處理程式

js
controller.abort(); // removes any/all event handlers associated with this controller

多個事件處理程式的互動

onevent IDL 屬性(例如,element.onclick = ...)和 HTML onevent 內容屬性(例如,<button onclick="...">)都指向同一個單一處理程式槽。HTML 在 JavaScript 訪問同一元素之前載入,因此通常 JavaScript 會替換 HTML 中指定的內容。使用addEventListener()新增的處理程式是獨立的。使用onevent不會移除或替換使用addEventListener()新增的監聽器,反之亦然。

當事件被分派時,監聽器分階段呼叫。有兩個階段:捕獲冒泡。在捕獲階段,事件從最高的祖先元素開始,沿著 DOM 樹向下移動,直到到達目標。在冒泡階段,事件沿相反方向移動。事件監聽器預設在冒泡階段監聽,它們可以透過在addEventListener()中指定capture: true來在捕獲階段監聽。在一個階段內,監聽器按照註冊的順序執行。onevent處理程式在第一次變為非空時註冊;後來的重新分配只改變其回撥,不改變其在順序中的位置。

呼叫Event.stopPropagation()可以阻止在傳播鏈中稍後呼叫其他元素的監聽器。Event.stopImmediatePropagation()還可以阻止呼叫同一元素上剩餘的監聽器。

規範

規範
DOM
# events
HTML
# events-2

另見