onclick =“”与事件处理程序

如果我想要一个函数被执行,我更喜欢做内联js:

<p id="element" onclick="doSomething();">Click me</p> 

因为它更容易debugging。

但是,我听到有人说不要使用内联js,而是:

 document.getElementById('element').onclick = doSomething; 

为什么推荐使用js事件监听器?

基本上它与整体保持一切,我相信。 所以保持HTML / CSS / JS全部分开。 它使您的HTML更整洁,我认为,更容易导航没有。

然后当/如果你需要做大的改变,你有足够的空间,不得不将内联JS转移到外部文件,或者如果你想将同一个函数应用到多个button,那么代码就less了。 less代码是一个更快乐的地方

如果你有你的JS文件正确,并彻底logging,然后由外部人导航他们是eaiser

反对内联事件处理程序的一个重要论点,以及其他答案所讨论的论点是表示与逻辑的分离 。

然而,实际上IMO有一个更大的问题:如何评估内联事件处理程序的难以捉摸的方式。

正如你现在所看到的那样, on*属性的内容将被用作事件处理函数的主体 。 但是这个function有什么特点?

其中一个令人惊讶的是, 一些祖先元素元素本身的 属性在内联事件处理程序的范围之内。

这里是一个例子 :

 <form> <input name="foo" /> <button type="button" onclick="console.log(foo); console.log(window.foo);"> Click me </button> <div onclick="console.log(foo);">Click me as well!</div> </form> 

点击button日志

 [object HTMLInputElement] undefined 

在控制台。 window.fooundefined的事实告诉你,没有全局variablesfoo 。 那么variablesfoo从哪里来呢? 为什么console.log(foo)logginginput元素,而不是抛出一个引用错误?
因为form元素的属性在事件处理程序的范围内,并且form元素对于它包含的每个指定表单控制元素都有一个属性。 你可以用console.log(document.querySelector('form').foo)轻松地testing这个。

现在,单击div元素实际上会引发一个引用错误:

ReferenceError: foo is not defined

所以显然, form元素只在表单控制元素的范围内,而不是任何后代。 这有多混淆?

同样, document对象的属性也在内联事件处理程序的范围内,这可能导致一些令人惊讶的错误 (你知道document有一个属性plugins ?)。

HTML5规范中正式规定了如何评估内联事件处理程序。 在步骤10中进行循环,特别是在描述范围链创build的地方。


结论

由于元素和内联事件处理程序之间的这种隐式连接,错误可能很难跟踪。 如果你只是想testing一些东西,那么使用内联事件处理程序当然是好的。 但是在生产代码中使用它们会带来更高的维护成本。

quirksmode.org上的文章解释了绑定事件处理程序及其(优点)的不同方式。

有很多原因可以避免内联JavaScript,也许最重要的是代码可维护性。

一个简单的例子(我只是为了演示而使用jQuery)。

 <p class="element" onclick="doSomething();">Click me</p> <p class="element" onclick="doSomething();">Click me</p> <p class="element" onclick="doSomething();">Click me</p> <p class="element" onclick="doSomething();">Click me</p> <p class="element" onclick="doSomething();">Click me</p> <p class="element" onclick="doSomething();">Click me</p> 

如果突然间你得到一个请求来改变你所有的段落来执行另一个function呢? 在你的例子中,你将不得不手动改变你的HTML代码。 但是,如果你select从JavaScript中分离HTML,你可以简单地这样做。

 <p class="element">Click me</p> <p class="element">Click me</p> <p class="element">Click me</p> <p class="element">Click me</p> <p class="element">Click me</p> <p class="element">Click me</p> $('.element').bind('click', doSomethingElse); 

HTML代码也是更清洁的,这使得devise人员可以专注于devise,而不用担心他们在涉及其他人的项目上工作时可能实际上破坏了某些东西。

编辑:提供我的评论下面的例子。

 Project = { // All the variables/constants/objects that need to be globally accessible inside the Project object. init : function(){ // Main entry point... this.MainMenu.init(); // Rest of the code which should execute the moment Project is initiated. } } Project.MainMenu = { // All the variables/constants/objects that need to be accessible only to MainMenu. init : function(){ // Is run immediatelly by Project.init() // Event handlers relevant to the main menu are bound here // Rest of the initialization code } } Project.SlideShow = { // All the variables/constants/objects that need to be accessible only to SlideShow. init : function(){ // Is run only on pages that really require it. // Event handlers for the slideshow. } } 

尽pipe别人可能会这样想,但我认为在标记中为听众提供了价值。 具体来说,它给了你更多的修改DOM节点的自由。 如果您通过JavaScript添加侦听器,那么当您replace任何父节点的innerHTML时,侦听器都将丢失。 如果你在标记中内联监听器,你可以克隆节点,对其进行修改,然后用刚刚克隆和修改的节点replace原始节点。

也许最好在特定的用例中描述它。 我想对文档的多个部分进行更改,而不会多次触发重排。 因此,在这种情况下,我可以克隆节点,对其进行任何更改(从其分离后不重新排列),然后使用修改的节点replace之前的节点(触发一个重排)。 内置监听器,这可以防止任何听众在更换过程中迷路。

你可以说相同的CSS和包括内联样式。 很容易不必通过CSS文件来查找当前的类/ id,或父/子元素您的工作。

绑定点击说10个不同的内联项目是否真的更好? 或者只是一个针对类的事件处理程序? 即使您不需要10个点击处理程序,将代码设置为可维护性也是一个更好的主意,并且可以升级。

我没有意识到使用内联处理程序的优点,以后再附加处理程序。 根据我的经验,当我必须处理dynamic元素时,我更喜欢使用内联方法,例如,我想为每个图像添加一个处理程序,并根据其他数据(如db中的图像)更改图像数量。 在这种情况下,使用内联允许我为每个图像添加一个处理程序,否则我必须重新计算JavaScript文件中的图像数量以附加和处理程序到每个图像。

当然,当你可以使用像jQuery的库,你可以很容易地得到内联列表的元素是没有用的

我看到有些人认为,关于演示和业务逻辑需要分开关注。

在他的例子OP确实显示了这种分离! 内联事件处理程序中没有任何逻辑,只是一个函数引用/调用,将在“click”事件上执行…逻辑本身可以在别处单独维护。

由于逻辑stream程的可发现性,我个人更喜欢这种方法。 如果我以前从来没有见过一个应用程序,那么我将开始我的代码遍历在DOM中,在那里它将清楚哪些事件处理程序正在运行以及哪些函数正在向处理程序。 通过使用,比如说一个“JQuery.On”事件的方法,通过浏览html,你将不知道哪些处理程序实际连接起来并提供了function。

仅仅提供函数指针的内联事件处理程序只是简单地连接事件,而不是将逻辑泄漏到演示文稿中。