首页 > 解决方案 > 引号中的 JavaScript onclick 处理程序给出不同的行为?

问题描述

我今天在编写一些演示代码时注意到了这种奇怪的行为,我很好奇发生了什么。尽管“Button 2”可以,但“Button”不起作用,即使它们的设置方式不同。我知道这与引用有关,但我很好奇为什么会这样。同样,如果我在引号中将函数传递给按钮 3,而不是将其直接附加到按钮 4 中,则按钮 4 有效,但按钮 3 无效。

另外,我认为鉴于按钮 2 有效,它会console.log("test")立即进行评估(类似于没有引号的情况),而是延迟到实际单击按钮。我知道这不是最好的方法,但出于好奇,我很好奇这里到底发生了什么。

document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
  <button id='hello'>Button</button>
  <button id='hello2' onclick='console.log("test")'>Button 2</button>
  <button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>
  <button id='hello4'>Button 4</button>

</div>
`;

document.getElementById("hello").onclick = 'console.log("test")';
document.getElementById("hello4").onclick = (e) => console.log("test");
<!DOCTYPE html>
<html>

<head>
	<title>Sandbox</title>
	<meta charset="UTF-8" />
</head>

<body>
	<div id="app"></div>

	<script src="src/index.js">
	</script>
</body>

</html>

标签: javascript

解决方案


当你分配给 时,你调用了一个 setter,它做的事情与使用分配的表达式onclick调用非常相似。addEventListener但是如果传递的表达式不是函数,两者addEventListener和都会默默地失败:onclick

document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
  <button id='hello'>Button</button>
`;

document.getElementById("hello").onclick = 'console.log("test")';
// nearly the same thing as:
document.getElementById("hello").addEventListener('click', 'console.log("test")');
<div id="app"></div>

该字符串不会被隐式强制转换为函数。

在第三个示例中,内联处理程序声明了一个函数,但从不执行它:

<button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>

这就像

button.addEventListener('click', function(event) {
  (e) => console.log("test")
});

侦听器运行,但侦听器不包含除未使用的函数表达式以外的任何内容,因此单击时您看不到任何内容。如果您添加日志语句,这可能会更清楚:

<button id='hello3' onclick='console.log("listener running;"); (e) => console.log("test")'>Button 3</button>

一般来说,你不应该使用内联处理程序;它们需要全局污染,难以管理,存在字符串和 HTML 转义问题,并且几乎被普遍认为是不好的做法。相反,使用addEventListener并始终传递函数而不是字符串,以便正确添加侦听器。


推荐阅读