javascript - 重构:希望单个函数/事件处理程序做同样的事情
问题描述
从我的代码中可以看出,我是编程和 JS 的新手。页面上的背景颜色和文本会根据<li>
单击的目标标记而变化,例如函数、对象、数组或使用eventListeners
事件处理程序的 if 语句。
我在这里寻找灵感,以便最终了解编程的真正工作原理。
请参阅下面的代码。
let navLink1 = document.querySelector('color1');
let navLink2 = document.querySelector('color2');
let navLink3 = document.querySelector('color3');
let navLink4 = document.querySelector('color4');
let p1 = document.querySelector('para');
navLink1.addEventListener('click', function (e) {
document.body.style.background = "color1";
document.innerHTML(p1) = "New text!";
});
navLink2.addEventListener('click', function (e) {
document.body.style.background = "color2";
document.innerHTML(p1) = "New text!";
});
navLink3.addEventListener('click', function (e) {
document.body.style.background = "color3";
document.innerHTML(p1) = "New text!";
});
navLink4.addEventListener('click', function (e) {
document.body.style.background = "color4";
document.innerHTML(p1) = "New text!";
});
<ul class ='nav'>
<li class ='color1'><a href=''>color1</a></li>
<li class ='color2'><a href=''>color2</a></li>
<li class ='color3'><a href=''>color3</a></li>
<li class ='color4'><a href=''>color4</a></li>
</ul>
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<p class ='para'>This is (color)</p>
<!-- if color1 is clicked in the menu then the <body> background will be changed to color1 and the innerHTML will also be changed to color1. The background color and targeted text changes according to the menu item clicked ->
解决方案
该代码存在一些问题,但基本上:是的,您可以使用单个事件处理程序来处理所有四个链接。这个过程称为“事件委托”——将事件的处理委托给某个祖先元素。在这种情况下,这ul
是放置click
处理程序的好地方。click
事件“冒泡”从目标元素 (the li
) 到它的父元素,然后是它li
的父元素等等,所以我们可以ul
通过在ul
.
看评论:
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an element that has a `data-color` attribute.
const li = event.target.closest("[data-color]");
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (li && this.contains(li)) {
// Get the color from the attribute
const color = li.getAttribute("data-color");
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li data-color="#E0E0E0">color1</li>
<li data-color="#D0D0D0">color2</li>
<li data-color="#C0C0C0">color3</li>
<li data-color="#B0B0B0">color4</li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>
更多的
如果你想用元素来做这件事a
(所以我们在各种用户手势上获得默认的选项卡和“激活”,比如按下Enter),我们可以做同样的事情,只需调用告诉浏览器event.preventDefault()
不要跟随href
. a
这样做时,通常最好让href
用户知道它要做什么,所以我们可以使用它而不是data-*
属性:
// The prefix used on `a` element `href`s:
const prefix = "#set-color-";
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an `a` element whose `href` *starts with* the
// text `set-color-`
const anchor = event.target.closest(`a[href^="${prefix}"]`);
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (anchor && this.contains(anchor)) {
// Get the color from the `href` by grabbing the part after the
// prefix
const color = anchor.getAttribute("href").substring(prefix.length);
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
// Prevent the default of following the anchor
event.preventDefault();
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li><a href="#set-color-#E0E0E0">color1</a></li>
<li><a href="#set-color-#D0D0D0">color2</a></li>
<li><a href="#set-color-#C0C0C0">color3</a></li>
<li><a href="#set-color-#B0B0B0">color4</a></li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>