搜尋
首頁web前端css教學簡化事件處理程序背後的思考

The Thinking Behind Simplifying Event Handlers

事件用於響應用戶點擊、鍵盤聚焦鏈接以及更改表單文本等操作。剛開始學習JavaScript 時,我編寫了複雜的事件監聽器。最近,我學習瞭如何減少代碼量和監聽器數量。

讓我們從一個簡單的例子開始:幾個可拖動的方塊。我們想向用戶顯示他們拖動的彩色方塊。

<div draggable="true">
    R
  </div>
  <div draggable="true">
    Y
  </div>
  <div draggable="true">
    G
  </div>
<p>拖動一個方塊</p>

直觀的做法

剛開始學習JavaScript 事件時,我為每個元素編寫了單獨的事件監聽器函數。這是一個常見的模式,因為它是最簡單的入門方法。我們希望每個元素都有特定的行為,因此可以使用每個元素的特定代碼。

 document.querySelector('#red').addEventListener('dragstart', evt => {
  document.querySelector('#dragged').textContent = 'Dragged red';
});

document.querySelector('#yellow').addEventListener('dragstart', evt => {
  document.querySelector('#dragged').textContent = 'Dragged yellow';
});

document.querySelector('#green').addEventListener('dragstart', evt => {
  document.querySelector('#dragged').textContent = 'Dragged green';
});

減少重複代碼

該示例中的事件監聽器非常相似:每個函數都顯示一些文本。此重複代碼可以折疊到一個輔助函數中。

 function preview(color) {
  document.querySelector('#dragged').textContent = `Dragged ${color}`;
}

document
  .querySelector('#red')
  .addEventListener('dragstart', evt => preview('red'));
document
  .querySelector('#yellow')
  .addEventListener('dragstart', evt => preview('yellow'));
document
  .querySelector('#green')
  .addEventListener('dragstart', evt => preview('green'));

這樣更簡潔,但仍然需要多個函數和事件監聽器。

利用Event 對象

Event 對像是簡化監聽器的關鍵。調用事件監聽器時,它還會將Event 對像作為第一個參數發送。此對象包含一些數據來描述發生的事件,例如事件發生的時間。為了簡化我們的代碼,我們可以使用evt.currentTarget屬性,其中currentTarget指的是附加事件監聽器的元素。在我們的示例中,它將是三個彩色方塊之一。

 const preview = evt => {
  const color = evt.currentTarget.id;
  document.querySelector('#dragged').textContent = `Dragged ${color}`;
};

document.querySelector('#red').addEventListener('dragstart', preview);
document.querySelector('#yellow').addEventListener('dragstart', preview);
document.querySelector('#green').addEventListener('dragstart', preview);

現在只有一個函數而不是四個函數了。我們可以將完全相同的函數作為事件監聽器重用,而evt.currentTarget.id將根據觸發事件的元素具有不同的值。

使用事件冒泡

最後一個更改是減少代碼中的行數。與其將事件監聽器附加到每個方塊,不如將單個事件監聽器附加到包含所有彩色方塊的元素。

事件在觸發時從事件起源的元素(其中一個方塊)開始。但是,它不會就此停止。瀏覽器會轉到該元素的每個父元素,並調用其上的任何事件監聽器。這將持續到文檔的根元素(HTML 中的標籤)。此過程稱為“冒泡”,因為事件像氣泡一樣上升到文檔樹中。將事件監聽器附加到section 元素將導致焦點事件從被拖動的彩色方塊冒泡到父元素。我們還可以利用evt.target屬性,該屬性包含觸發事件的元素(其中一個方塊),而不是附加事件監聽器的元素( section元素)。

 const preview = evt => {
  const color = evt.target.id;
  document.querySelector('#dragged').textContent = `Dragged ${color}`;
};

document.querySelector('section').addEventListener('dragstart', preview);

現在我們已經將許多事件監聽器減少到只有一個了!對於更複雜的代碼,效果會更好。通過利用Event 對象和冒泡,我們可以控制JavaScript 事件並簡化事件處理程序的代碼。

點擊事件呢?

evt.targetdragstartchange等事件非常有效,在這些事件中,只有少量元素可以接收焦點或更改輸入。

但是,我們通常希望監聽點擊事件,以便我們可以響應用戶點擊應用程序中的按鈕。點擊事件會針對文檔中的任何元素觸發,從大型div 到小型span。

讓我們將我們的可拖動彩色方塊改為可點擊的。

<div draggable="true">
    R
  </div>
  <div draggable="true">
    Y
  </div>
  <div draggable="true">
    G
  </div>
<p>點擊一個方塊</p>
const preview = evt => {
  const color = evt.target.id;
  document.querySelector('#clicked').textContent = `Clicked ${color}`;
};

document.querySelector('section').addEventListener('click', preview);

在測試此代碼時,請注意,有時不會附加到“Clicked”,而不是點擊方塊時。它不起作用的原因是每個方塊都包含一個可以點擊的<span></span>元素,而不是可拖動的<div>元素。由於span 沒有設置ID,因此<code>evt.target.id屬性為空字符串。我們只關心代碼中的彩色方塊。如果我們在方塊內某處點擊,我們需要找到父方塊元素。我們可以使用element.closest()來查找最接近被點擊元素的父元素。

 const preview = evt => {
  const element = evt.target.closest('div[draggable]');
  if (element != null) {
    const color = element.id;
    document.querySelector('#clicked').textContent = `Clicked ${color}`;
  }
};

現在我們可以對點擊事件使用單個監聽器了!如果element.closest()返回null,則表示用戶在彩色方塊之外的某處點擊,我們應該忽略該事件。

更多示例

以下是一些其他示例,用於演示如何利用單個事件監聽器。

列表

一個常見的模式是擁有一個可以交互的項目列表,其中新的項目是使用JavaScript 動態插入的。如果我們為每個項目附加事件監聽器,那麼每次生成新元素時,代碼都必須處理事件監聽器。

<div id="buttons-container"></div>
<button id="add">添加新按鈕</button>
let buttonCounter = 0;
document.querySelector('#add').addEventListener('click', evt => {
  const newButton = document.createElement('button');
  newButton.textContent = buttonCounter;

  // 每次點擊“添加新按鈕”時創建一個新的事件監聽器newButton.addEventListener('click', evt => {

    // 點擊時,記錄被點擊按鈕的編號。
    document.querySelector('#clicked').textContent = `Clicked button #${newButton.textContent}`;
  });

  buttonCounter ;

  const container = document.querySelector('#buttons-container');
  container.appendChild(newButton);
});

通過利用冒泡,我們可以在容器上使用單個事件監聽器。如果我們在應用程序中創建許多元素,這會將監聽器的數量從n 減少到兩個。

 let buttonCounter = 0;
const container = document.querySelector('#buttons-container');
document.querySelector('#add').addEventListener('click', evt => {
  const newButton = document.createElement('button');
  newButton.dataset.number = buttonCounter;
  buttonCounter ;

  container.appendChild(newButton);
});
container.addEventListener('click', evt => {
  const clickedButton = evt.target.closest('button');
  if (clickedButton != null) {
    // 點擊時,記錄被點擊按鈕的編號。
    document.querySelector('#clicked').textContent = `Clicked button #${clickedButton.dataset.number}`;
  }
});

表單

也許有一個包含許多輸入的表單,我們想將所有用戶響應收集到單個對像中。





let responses = {
  name: '',
  email: '',
  password: ''
};

document
  .querySelector('input[name="name"]')
  .addEventListener('change', evt => {
    const inputElement = document.querySelector('input[name="name"]');
    responses.name = inputElement.value;
    document.querySelector('#preview').textContent = JSON.stringify(responses);
  });
document
  .querySelector('input[name="email"]')
  .addEventListener('change', evt => {
    const inputElement = document.querySelector('input[name="email"]');
    responses.email = inputElement.value;
    document.querySelector('#preview').textContent = JSON.stringify(responses);
  });
document
  .querySelector('input[name="password"]')
  .addEventListener('change', evt => {
    const inputElement = document.querySelector('input[name="password"]');
    responses.password = inputElement.value;
    document.querySelector('#preview').textContent = JSON.stringify(responses);
  });

讓我們改用父<form></form>元素上的單個監聽器。

 let responses = {
  name: '',
  email: '',
  password: ''
};

document.querySelector('form').addEventListener('change', evt => {
  responses[evt.target.name] = evt.target.value;
  document.querySelector('#preview').textContent = JSON.stringify(responses);
});

結論

現在我們知道如何利用事件冒泡和事件對象將復雜的事件處理程序混亂簡化為幾個……有時甚至減少到一個!希望本文能幫助您從新的角度思考事件處理程序。我知道在我早期的開發生涯中花費大量時間編寫重複的代碼來完成同樣的事情之後,這對我來說是一個啟示。

以上是簡化事件處理程序背後的思考的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
模擬鼠標運動模擬鼠標運動Apr 22, 2025 am 11:45 AM

如果您曾經在現場演講或課程中必須顯示一個互動動畫,那麼您可能知道它並不總是那麼容易與您的幻燈片進行互動

通過Astro Action和Fuse.js為搜索提供動力通過Astro Action和Fuse.js為搜索提供動力Apr 22, 2025 am 11:41 AM

對於Astro,我們可以在構建過程中生成大部分網站,但是有一小部分服務器端代碼可以使用Fuse.js之類的搜索功能來處理搜索功能。在此演示中,我們將使用保險絲搜索一組個人“書籤”

未定義:第三個布爾值未定義:第三個布爾值Apr 22, 2025 am 11:38 AM

我想在我的一個項目中實現一條通知消息,類似於您在保存文檔時在Google文檔中看到的信息。換句話說,一個

捍衛三元聲明捍衛三元聲明Apr 22, 2025 am 11:25 AM

幾個月前,我正在使用黑客新聞(就像一個人一樣),並且遇到了一篇(現已刪除的)文章,內容涉及不使用if語句。如果您是這個想法的新手(就像我

使用網絡語音API進行多語言翻譯使用網絡語音API進行多語言翻譯Apr 22, 2025 am 11:23 AM

自科幻小說以來,我們就幻想著與我們交談的機器。今天這很普遍。即便如此,製造的技術

JetPack Gutenberg塊JetPack Gutenberg塊Apr 22, 2025 am 11:20 AM

我記得當古騰堡被釋放到核心時,因為那天我在WordCamp我們。現在已經過去了幾個月,所以我想我們越來越多的人

在VUE中創建可重複使用的分頁組件在VUE中創建可重複使用的分頁組件Apr 22, 2025 am 11:17 AM

大多數Web應用程序背後的想法是從數據庫中獲取數據,並以最佳方式將其呈現給用戶。當我們處理數據時

使用'盒子陰影”和剪輯路徑一起使用'盒子陰影”和剪輯路徑一起Apr 22, 2025 am 11:13 AM

讓我們在一個情況下做一些似乎有意義的事情的情況下逐步進行一些逐步,但是您仍然可以用CSS欺騙來完成它。在這個

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。