不同放置JavaScript代码的<a>方法有什么区别?

87

我见过在 <a> 标签中嵌入 JavaScript 代码的以下方法:

function DoSomething() { ... return false; }
  1. <a href="javascript:;" onClick="return DoSomething();">link</a>
  2. <a href="javascript:DoSomething();">link</a>
  3. <a href="javascript:void(0);" onClick="return DoSomething();">link</a>
  4. <a href="#" onClick="return DoSomething();">link</a>

在假设用户已启用JavaScript的情况下,为了让代码具有可读性和调试性,我个人喜欢选项2。虽然一些人推荐选项4,因为它提供给用户一个“真正的”链接,但实际上,“#”并不是一个“真正的”链接,它什么也不会做。以上四种方法在已启用JavaScript时都能使用。

相关问题:JavaScript链接的href属性应该使用“#”还是“javascript:void(0)”?


小语法问题:选项#2应该是 - <a href="javascript:DoSomething();">link</a> 没有 "return" - DRosenfeld
请将已接受的答案更改为 @eyelidlessness 的回答。我认为这是最好的方法,因为它关心语义。 - Michał Perłakowski
7个回答

69

我非常喜欢Matt Kruse的JavaScript最佳实践文章。在其中,他指出使用 href 属性来执行JavaScript代码是一个不好的主意。即使你已经声明你的用户必须启用JavaScript,也没有理由不提供一个简单的HTML页面作为所有JavaScript链接的指向,以备某些人在登录后禁用了JavaScript。我强烈建议您仍然允许这种回退机制。像这样做将遵循“最佳实践”,并实现您的目标:

<a href="javascript_required.html" onclick="doSomething(); return false;">go</a>

4
由于 href 值将显示在用户的状态栏中(底部的那个栏),我建议考虑使用更加用户友好的链接格式,例如 "js.html?doSomething"。页面仍然可以是静态 HTML,这样用户就可以清楚地看到链接之间的不同。请注意不要改变原来的意思。 - Gene
7
您可以使用title属性覆盖此值,例如:<a href="javascript_required.html" title="执行某些操作" onclick="doSomething(); return false;">前往</a>。 - Conspicuous Compiler
最佳实践应该是记录对javascript_required.html页面的请求,并记录导致错误的函数。 - Timo Huovinen
2
你有没有考虑过对SEO的影响? - DanielBlazquez
Matt Kruse的javascripttoolbox.com似乎已经下线并出售。 - showdev

10

如果可以使用addEventListener/attachEvent,为什么要这样做呢?如果没有href等价物,请不要使用<a>标签,而是使用<button>标签并相应地进行样式设置。


10
在许多情况下,使用按钮而不是链接并不是可行的选项。 - nickf
2
因为它看起来很丑。您可以在链接旁边添加图标。他们很难在各个浏览器上格式化相同。而且通常人们正在转向链接而不是按钮-看看大多数 Stack Overflow。 - Darryl Hein
2
它看起来难看?其实它可以看起来像你想要的样子。事实上,我认为按钮比链接具有更多的样式灵活性,因为它们是行内元素,但可以在各种浏览器中正确地使用填充。任何链接能够实现的效果,按钮都可以用CSS实现。 - eyelidlessness
3
跨度无法获得键盘焦点。 - bobince
3
按钮是(咳咳)语义上正确的。Span 在语义上毫无意义。按钮在语义上恰好符合作者的意图。 - eyelidlessness
显示剩余6条评论

5

你忘记了另一种方法:

5: <a href="#" id="myLink">Link</a>

使用以下JavaScript代码:
document.getElementById('myLink').onclick = function() {
    // Do stuff.
};

我不能评论哪个选项有最好的支持或哪个在语义上最好,但我只想说我更喜欢这种样式,因为它将你的内容与JavaScript代码分开。它将所有的JavaScript代码放在一起,这样更容易维护(特别是如果你应用到很多链接中),你甚至可以将它放在一个外部文件中,然后打包以减小文件大小并被客户端浏览器缓存。


7
如果你有20或30个不同的链接,并且它们都带有JS,那么这可能会变得相当繁琐,并且最终将产生大量的JS代码。 - Darryl Hein
1
@JKirchartz,如果回答背后有理由,我不明白为什么会被视为说教。如果你读了问题,它实际上是一个“这4个选项中哪个最好”的问题,而我只是指出了他没有考虑到的另一个选项。 - nickf
不要在选择A、B、C和D之间犹豫,选择E是没有意义的。无所谓,trololo。 - JKirchartz
3
@JKirchartz,恐怕你没有真正理解Stack Overflow的目的。如果有人问“在构建Web应用程序时哪种语言更好:Cobol还是Fortran?”告诉那个人他们没有考虑到所有可能性是可以接受的。问题显然不是在问“在这四种语言中只有这些哪个最好”。 - nickf
@nickf:“我理解尝试放置有效的URL而不仅仅是JavaScript代码的想法,以防用户没有启用JavaScript。但是为了本次讨论的目的,我需要假设JavaScript已启用(否则他们无法登录)。“和”是否有一个不受支持或非常糟糕的,当您知道用户已启用JavaScript时?“他已经知道并且正在询问这4个中哪一个最好。” - JKirchartz
显示剩余2条评论

3
<a href="#" onClick="DoSomething(); return false;">link</a>

我会这样做,或者:
<a href="#" id = "Link">link</a>
(document.getElementById("Link")).onclick = function() {
    DoSomething();
    return false;
};

根据情况而定。对于较大的应用程序,第二个选项是最好的,因为它可以 consolide 事件代码。


如果你有20或30个不同的JS链接,这可能会变得相当乏味,并最终导致大量的JS代码。 - Darryl Hein
代码中出现的错误可能非常难以进行调试。这些错误很容易出现,就像你的第一个例子一样。 :) - nickf

1
现代浏览器专用。
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
(function(doc){
    var hasClass = function(el,className) {
        return (' ' + el.className + ' ').indexOf(' ' + className + ' ') > -1;
    }
    doc.addEventListener('click', function(e){
      if(hasClass(e.target, 'click-me')){
          e.preventDefault();
          doSomething.call(e.target, e);
      }
    });
})(document);

function doSomething(event){
  console.log(this); // this will be the clicked element
}
</script>
<!--... other head stuff ...-->
</head>
<body>

<!--buttons can be used outside of forms https://dev59.com/-GYq5IYBdhLWcg3weAaj#14461672 -->
<button class="click-me">Button 1</button>
<input class="click-me" type="button" value="Button 2">

</body>
</html>

跨浏览器
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
(function(doc){
    var cb_addEventListener = function(obj, evt, fnc) {
        // W3C model
        if (obj.addEventListener) {
            obj.addEventListener(evt, fnc, false);
            return true;
        } 
        // Microsoft model
        else if (obj.attachEvent) {
            return obj.attachEvent('on' + evt, fnc);
        }
        // Browser don't support W3C or MSFT model, go on with traditional
        else {
            evt = 'on'+evt;
            if(typeof obj[evt] === 'function'){
                // Object already has a function on traditional
                // Let's wrap it with our own function inside another function
                fnc = (function(f1,f2){
                    return function(){
                        f1.apply(this,arguments);
                        f2.apply(this,arguments);
                    }
                })(obj[evt], fnc);
            }
            obj[evt] = fnc;
            return true;
        }
        return false;
    };
    var hasClass = function(el,className) {
        return (' ' + el.className + ' ').indexOf(' ' + className + ' ') > -1;
    }

    cb_addEventListener(doc, 'click', function(e){
      if(hasClass(e.target, 'click-me')){
          e.preventDefault ? e.preventDefault() : e.returnValue = false;
          doSomething.call(e.target, e);
      }
    });
})(document);

function doSomething(event){
  console.log(this); // this will be the clicked element
}
</script>
<!--... other head stuff ...-->
</head>
<body>

<!--buttons can be used outside of forms https://dev59.com/-GYq5IYBdhLWcg3weAaj#14461672 -->
<button class="click-me">Button 1</button>
<input class="click-me" type="button" value="Button 2">

</body>
</html>

您可以在文档准备就绪之前运行此操作,单击按钮将起作用,因为我们将事件附加到文档。

来源:


1

我注意到的一个区别是:

<a class="actor" href="javascript:act1()">Click me</a>

而且还有这个:
<a class="actor" onclick="act1();">Click me</a>

如果在任一情况下您都有:

<script>$('.actor').click(act2);</script>

对于第一个例子,act2将在act1之前运行;而在第二个例子中,则相反。


1

方法二在FF3和IE7中存在语法错误。 我更喜欢方法一和方法三,因为方法四会用'#'污染URI,尽管打字较少... 显然,正如其他回复所指出的那样,最好的解决方案是将HTML与事件处理分开。


第二种方法是什么?问题的顺序不会像你看到它们时那样保持不变。 - Diodeus - James MacFarlane
如果确保使用return false,方法#4不会破坏URI,因此可能是最好的(列出的方法中)。 - Már Örlygsson
2
@Diodeus,我相信Pier指的是问题中的编号列表,实际上自从问题首次发布以来就一直存在。 - eyelidlessness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接