如何将事件侦听器应用于具有相同类的多个元素,并让每个元素独立响应



我的HTML中有一个元素列表,如下所示:

<div class='container'>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
<script type="text/javascript" src="script.js"></script>
</div>

我试图做到这一点,以便我点击的每个元素都会将元素中的动物记录到控制台上。 这是我的尝试:

const selection = document.querySelectorAll(".zone");

selection.forEach(element => {
element.addEventListener('click', pickSelection(element))
})

function pickSelection(animal) {
console.log(animal.textContent)
}

但是当我单击任何元素时,它没有返回任何内容。 但是,一旦我将事件侦听器更改为此,它就开始工作:

selection.forEach(element => {
element.addEventListener('click', () => pickSelection(element))
})

为什么它在代码的第二个版本中工作而不是第一个版本? 在第一个版本中,我以为我是通过编写"pickSelection(element)"将元素参数传递给 pickSelect 函数的,但显然它只有在前面有"() =>"时才有效,但是这种符号有什么区别? 谢谢。

在第一个版本中,您正在执行pickSelection函数而不是传递其引用,addEventListener期望在触发特定事件时将函数引用作为回调。

但是由于您传递了undefinedpickSelection函数的返回值(因为您没有从pickSelection返回任何内容,因此默认情况下它返回undefined),因此它不起作用。

在第二个版本中,您实际上是将函数引用传递给addEventListner,这是一个箭头函数语法。

通过简单地传递引用pickSelection,以下内容也可以工作,但这次它将接收event对象。

const selection = document.querySelectorAll(".zone");
selection.forEach(element => {
element.addEventListener('click', pickSelection)
})
function pickSelection(event) {
//getting the event object from the callback, target refers to the current element clicked.
console.log(event.target.textContent)
}
<div class='container'>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
</div>

此行

element.addEventListener('click', pickSelection(element));

这实际上是

const temp = pickSelection(element);
element.addEventListener('click', temp);

你想要的是

element.addEventListener('click', pickSelection);

你看出区别了吗?

在此版本中

element.addEventListener('click', pickSelection(element))

您调用了该函数pickSelection并将其传递给element。然后传递任何pickSelection返回element.addEventListener

你想要/需要做的是将函数本身传递给element.addEventListener

此版本工作的原因

selection.forEach(element => {
element.addEventListener('click', () => pickSelection(element))
})

是因为您要将匿名函数传递给element.addEventListener。这些行可以翻译成这个

function anonymousFn1(element) {
function anonymousFn2() {
pickSelection(element);
}
element.addEventListener('click', anonymousFn2);
}
selection.forEach(anonymousFn1);

请注意,在功能上还有另一个区别。

在这个

element.addEventListener('click', pickSelection);

单击事件将一个 Event 对象传递给pickSelection而在另一个事件中,当称为 anonmousFn1forEach时创建的变量element被"关闭"(进行了闭包),因此当调用匿名 Fn2 时,使用该变量element

所以要让第一个工作,你真的需要这个

function pickSelection(event) {
const element = event.target;
console.log(element.textContent);
}

例:

const selection = document.querySelectorAll(".zone");
selection.forEach(element => {
element.addEventListener('click', pickSelection);
});
function pickSelection(event) {
element = event.target;
console.log(element.textContent);
}
<div class='container'>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
</div>

旁注:在每个元素上注册一个侦听器是一种不好的做法。请改用事件委派:

document.querySelector(`.container`).addEventListener(`click`, ({target}) => {
const el = target.closest(`.zone`);
if (el) {
console.log(el.textContent);
}
})
<div class='container'>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
<div class="zone green">  </div>
<div class="zone red">  </div>
<div class="zone blue">  </div>
<div class="zone yellow">  </div>
<div class="zone purple">  </div>
<div class="zone brown">  </div>
</div>

最新更新