简化事件处理程序背后的思考
事件用于响应用户点击、键盘聚焦链接以及更改表单文本等操作。刚开始学习 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.target
与 dragstart
和 change
等事件非常有效,在这些事件中,只有少量元素可以接收焦点或更改输入。
但是,我们通常希望监听点击事件,以便我们可以响应用户点击应用程序中的按钮。点击事件会针对文档中的任何元素触发,从大型 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中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...
