【问题标题】:Why does this setup of event handler not work?为什么这种事件处理程序设置不起作用?
【发布时间】:2018-06-09 13:52:17
【问题描述】:

这是我的html文件/tmp/test/test.html

<!DOCTYPE html>
<html>

  <head>
    <script src="../js/my.js" defer>
    </script>
  </head>

  <body>

    <p>This example uses the HTML DOM to assign an "onchange" event to an input element.</p>   

    Enter your name: <input type="text" id="fname">
    <p>When you leave the input field, a function is triggered which transforms the input text to upper case.</p>


  </body>
  </html>

这是我的 javascript 文件 /tmp/js/my.js,但事件处理程序的设置不起作用。为什么它不起作用,我该怎么做才能使它起作用?

function myFunction1(input) {
    input.value = input.value.toUpperCase();
}

document.getElementById("fname").onchange =  myFunction1;

如果我将 Javascript 文件的内容替换为

function myFunction2() {
    var x = document.getElementById("fname");
    x.value = x.value.toUpperCase();
}

document.getElementById("fname").onchange =  myFunction2;

事件处理程序有效。我想知道为什么这两种方法有这么大的区别?

在外部 Javascript 文件或 html 文件中指定事件处理程序的设置首选哪种方式?

【问题讨论】:

  • 事件处理器的第一个参数是Event对象;不是你的&lt;input&gt;(应该是this)。
  • @Xufox 这就是我知道我今天工作太久了:)

标签: javascript html node.js dom-events


【解决方案1】:

它不起作用的原因与脚本在外部文件中无关。这是因为您假设对 DOM 对象的引用作为参数 (input) 传递给函数,但事实并非如此。 input 实际上是对事件的引用。使用对象属性(onchange 等)或通过更现代和基于标准的.addEventListener() 设置的事件处理程序会自动传递对作为回调函数的第一个参数调用的事件的引用。

您的第二个版本有效,因为您不依赖参数来引用 DOM 对象,并且正确地使用 document.getElementById("fname") 获取对 DOM 对象的引用。但实际上,您不需要做任何特别的事情来获取对触发事件的 DOM 对象的引用,因为该对象将绑定到回调函数中的 this 关键字。

除此之外,您应该真正摆脱通过事件属性(如onchange 等)设置事件,因为这种方法将您限制为每个事件仅设置一个事件处理函数。而是使用现代标准,使用 element.addEventListener()

最后,要将文本内容全部更改为大写,您甚至不需要 JavaScript,因为仅使用 CSS 即可完成。

请参阅下面的示例,该示例显示了所有这些:

// Get your reference to DOM objects that you'll need just once, when the DOM is available
// And, set up events following modern standards:
document.getElementById("fname").addEventListener("change", myFunction);

// Event handlers are automatically passed a reference 
// to the event as the handler's first argument.
function myFunction(evt) {
  // Inside of an event handler for a DOM object, you can always
  // reference the DOM object that triggered the event via the target property
  // of the event (evt.target in this case) or, even simpler via the "this" keyword.
  console.log("Event: " + evt.type.toUpperCase()  + " was triggered by: " + this.nodeName + " " + this.id + " " + evt.target);
  this.value = evt.type;
}
/* You don't need JavaScript to convert content to upper case */
#fname { text-transform:uppercase; }
<p>This example uses the HTML DOM to assign an "onchange" event to an input element.</p>   

Enter your name: <input type="text" id="fname">
<p>When you leave the input field (just hit TAB after inputting some data), the CHANGE event callback function is triggered.</p>

【讨论】:

  • 谢谢。我正在关注这个示例stackoverflow.com/a/18893556/156458,其中对DOM 对象的引用被传递给事件处理函数check()。为什么check() 不期望接受一个事件呢?
  • First parameter to event handler。事件属性非常不同。
  • @Tim 该示例使用 HTML 属性来设置事件处理,这是一种已有 20 年历史的方法,不应再使用。这种方法不是引用函数,而是直接调用它,并且在这种方法中,事件不会自动传递给函数。
  • 谢谢。我可以从事件参数中获取 DOM 对象,而不是第二种方式的 document.getElementById("fname") 吗?如果是,是否比document.getElementById("fname") 更好?
  • @Tim 是的,您可以使用evt.target。但是,如果您查看我更新的答案,您会发现您不需要做任何事情来获取引用,因为this 将绑定到触发事件的 DOM 对象。这是首选,因为它不需要额外的努力来获得参考。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多