onclick =“”vs事件处理程序

时间:2011-08-04 12:34:45

标签: javascript event-handling inline-code

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

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

因为它更容易调试。

然而,我听到有人说不使用内联js,并且:

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

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

8 个答案:

答案 0 :(得分:39)

反对内联事件处理程序的一个重要论点,其他答案解决的论点是the separation of presentation and logic

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

如您所知,on*属性的内容将用作事件处理函数的 body 。但是这个功能有什么特点?

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

<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日志

<input name="foo"></input>
undefined

在控制台中。 window.fooundefined的事实告诉您没有全局变量foo。那么变量foo来自何处?为什么console.log(foo)记录输入元素而不引发引用错误?
因为form元素的属性在事件处理程序的范围内,并且form元素具有它包含的每个命名表单控件元素的属性。您可以使用console.log(document.querySelector('form').foo)轻松测试此内容。

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

  

ReferenceError: foo is not defined

显然form元素只在表单控件元素的范围内,而不是任何后代。这有多令人困惑?

同样,properties of the document对象也在内联事件处理程序的范围内,can lead to some surprising bugs(你知道document有一个属性plugins吗?)。< / p>

如何评估内联事件处理程序是在HTML5 spec中形式化的。在步骤10中有一个循环,特别是描述了范围链创建。


<强>结论

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

The articles at quirksmode.org解释了绑定事件处理程序及其(dis)优势的不同方法。

答案 1 :(得分:13)

基本上它与整体保持一致我相信。因此,请将HTML / CSS / JS全部分开。它使你的HTML更整洁,而且我认为更容易导航。

然后当/如果你需要进行大的更改时,你有足够的空间不得不将内联JS移动到外部文件或者如果你想将相同的函数应用于多个按钮,那么它的代码就更少了。少代码是一个更幸福的地方

如果您的JS文件正确,并且有完整的文档,那么由外部人员导航它们就是eaiser

答案 2 :(得分:4)

有很多理由可以避免使用内联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>

如果您突然收到更改所有段落以执行其他功能的请求,该怎么办?在您的示例中,您必须在HTML代码中手动更改所有内容。但是,如果您选择将HTML与JavaScript分开,则可以这样做。

<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代码也更清晰,允许设计人员专注于设计而不用担心他们在处理涉及其他人的项目时可能会破坏某些东西。

编辑:为我的评论提供示例。

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.
    }
}

答案 3 :(得分:3)

尽管其他人可能会想到,但我认为在标记中内联听众有赎回的价值。具体来说,它为您提供了更多自由来修改DOM节点。如果您通过JavaScript添加侦听器,则在替换任何父节点的innerHTML时,侦听器将丢失。如果您在标记中内联侦听器,则可以克隆节点,对其进行修改,然后将原始节点替换为刚刚克隆和修改的节点。

或许最好在特定用例中描述它。我想对文档的多个部分进行更改,而不会多次触发重排。所以在这种情况下,我可以克隆节点,对它进行任何更改(自分离后没有重排),然后用修改后的节点替换前一节点(触发一次重排)。使用内联侦听器,可以防止任何侦听器在替换期间丢失。

答案 4 :(得分:2)

我看到有人说需要将关于演示和业务逻辑的问题分开。

他的例子中的OP确实显示了这种分离!内联事件处理程序中没有逻辑,只是一个函数引用/调用将在&#34; click&#34;上执行。事件...逻辑本身可以在其他地方单独维护。

由于逻辑流可发现性,我个人更喜欢这种方法。如果我以前从未见过应用程序......首先我将开始我的代码遍历是在DOM中,并且在那里将清楚哪些事件处理程序正在运行以及哪些函数正在提供逻辑给处理者。使用,说一个&#34; JQuery.On&#34;事件方法,只需浏览一下html就不知道哪些处理程序实际连接并提供了功能。

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

答案 5 :(得分:0)

你可以对CSS说同样的内容,包括内联样式。很容易不必通过css文件来查找当前的类/ id,或者你正在使用的父/子元素。

绑定点击内联10个不同的项目真的更好吗?或者只是一个针对类的事件处理程序?即使您不需要10个点击处理程序,最好还是设置代码以实现可维护性和升级。

答案 6 :(得分:0)

我不知道使用内联处理程序和以后附加处理程序的优势。根据我的经验,当我必须处理动态元素时,我更喜欢使用内联方法,例如,如果我想为每个图像添加处理程序,并且图像的数量根据其他数据(db中的ex图像)而变化。在这种情况下,使用内联允许我为每个图像添加处理程序,否则我必须重新计算javascript文件中的图像数量以附加和处理每个图像。

当然,当你可以使用像jQuery这样的库时,你可以轻松获取内联元素列表是没用的

答案 7 :(得分:0)

除了编码标准视角

使用属性:

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

如果再次添加相同的属性(见下文) - 会考虑最新的属性。

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

使用事件处理程序:

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

并且假设您添加了以下行

document.getElementById('element').onclick = doSomethingMore; 两个处理程序都被调用。