为什么使用javascript:"协议"链接是不好的做法?

56
在20世纪90年代,有一种流行趋势是直接将Javascript代码放入 href属性中,就像这样:
<a href="javascript:alert('Hello world!')">Press me!</a>

然后突然间我停下来看它。它们全部被类似以下的东西所替换:

<a href="#" onclick="alert('Hello world!')">Press me!</a>

如果一个链接的唯一目的是触发Javascript代码,而且没有真正的href目标,为什么鼓励使用onclick属性而不是href属性?


13
它并没有被弃用,只是不良实践。使用 onclick 属性也是如此。搜寻“无侵入式 JavaScript”和“渐进增强”以获取最佳实践。 - Gabriele Petrioli
@Gaby:那么“bad practice”和“deprecated”有什么区别呢? - zneak
4
“Deprecated” 的意思是这些功能在未来很可能不被支持。 - Gabriele Petrioli
1
我甚至认为使用<a>标签来假装它是一个链接到页面的坏习惯(或实践?),当它实际上只是一个“触发JS操作”的东西。我会考虑使用<span class="js-trigger">按我</span>,并通过将相关的JavaScript代码放入单独的JS文件中来解耦。 - Adriano
10个回答

56

执行上下文是不同的,为了看到这一点,请尝试使用以下链接:

<a href="javascript:alert(this.tagName)">Press me!</a> <!-- result: undefined -->
<a href="#" onclick="alert(this.tagName)">Press me!</a> <!-- result: A -->

javascript: 在全局上下文中执行,而不是作为元素的方法执行,这通常不是您想要的。在大多数情况下,您正在处理或与操作的元素相关的内容,最好在该上下文中执行。

此外,这样做更加简洁,虽然我根本不会使用内联脚本。查看任何处理这些事情的框架,以更加清晰的方式处理这些事情。例如,使用jQuery:

$('a').click(function() { alert(this.tagName); });

6
简单澄清一下 - 当你从href属性中调用javascript:this时,它是对窗口DOM对象的引用。 - matt lohkamp
1
感谢您解释了区别并提出了更好的方法。 - zneak
1
我觉得有意思的是,社区青睐并被选中的回答关注于使用 javascript: 协议对开发者所造成的不便,而不是其对交付成果质量的影响…这让我想起了电梯测试;http://www.codinghorror.com/blog/2007/09/can-your-team-pass-the-elevator-test.html - Richard JP Le Guen
@Richard - 这也有一个优点,即它位于外部且缓存文件中,不会作为页面的一部分在每个轮回中被下载...我认为出于许多原因,这对开发人员来说既有质量又有便利性更好。 - Nick Craver
@Nick Craver - 这是真的...我对措辞和内容一样感到好奇;对我来说,它感觉像是一个脚注/事后想法。并不是说我不同意你的任何观点 :) - Richard JP Le Guen

19

实际上,这两种方法都被认为已经过时了。开发人员现在鼓励将所有JavaScript分离到外部JS文件中,以便将逻辑和代码与真正的标记分开。

原因在于它创建了更易于维护和调试的代码,并且还促进了Web标准和可访问性。想象一下:看看你的示例,如果在页面上有数百个类似的链接,并且需要使用外部JS引用将alert行为更改为其他函数,那么您只需要更改一个JS文件中的单个事件绑定,而不是一遍又一遍地复制和粘贴一堆代码或执行查找和替换。


10

两个原因:

  1. 糟糕的编程实践:
    HREF标签用于指示有超链接引用到另一个位置。将同样的标签用于非实际带用户前往其他地方的javascript函数是糟糕的编程实践。

  2. SEO问题:
    我认为网络爬虫使用HREF标签在整个网站上爬行并链接所有连接部分。通过加入javascript,我们打破了这个功能。

  3. 破坏无障碍性:
    我认为一些屏幕阅读器将无法执行javascript,并且可能不知道如何处理javascript,而他们期望看到超链接。用户期望在浏览器状态栏悬停链接时看到一个链接,而他们将看到类似“javascript:”的字符串,这可能会使他们困惑等。

  4. 你还停留在20世纪90年代:
    主流建议是将javascript放在单独的文件中,而不是像20世纪90年代那样与页面的HTML混合。

希望对你有所帮助。


我不认为SEO是一个有效的论点,因为它们非常能够找出哪些链接可以跟随,哪些不能。我会接受你关于屏幕阅读器的论点(我肯定会喜欢听到计算机语音大声朗读JavaScript代码),但状态栏的问题对我来说似乎有些夸张。 - zneak
1
@zneak - 或许我应该把状态栏的注释从“可能会让他们困惑”改成“可能会让他们感到烦恼”。从个人经验来看,当我不想离开当前页面时,我喜欢使用Shift+单击/Ctrl+单击链接以在新窗口中打开它们,而当这种方式失效时,我希望去找到最初破坏它的开发者 :) - Sunny
这是一个糟糕的编程实践,href标签没有被创建来指示JS代码的触发器。 - Adriano

7

我经常在新标签页打开很多链接,但只看到javascript:void(0)。所以你不仅会惹恼我,也会惹恼你自己(因为Google也会看到同样的情况)。

另一个原因(其他人也提到过)是不同的语言应该分开成不同的文档。为什么?嗯,有以下几个原因:

  • 混合语言并不被大多数IDE和验证器支持。将CSS和JS嵌入HTML页面(或其他任何东西)基本上破坏了检查嵌入语言正确性的机会。有时,嵌入语言也是如此。(PHP或ASP文档不是有效的HTML。)您不希望在运行时才出现语法错误或不一致性。
  • 另一个原因是为了更清晰地区分需要指定的内容类型:HTML用于内容,CSS用于布局,JS通常用于更多的布局和外观。它们之间并不是一对一的映射:您通常希望将布局应用于整个内容元素类别(因此使用CSS),以及外观和感觉(因此使用jQuery)。它们可能会在不同的时间由不同的人进行更改(实际上,内容通常是动态生成的)。因此,将它们保留在单独的文档中是有意义的。

主要是因为第一点而投了赞成票。试图在新标签页中打开链接,结果在地址栏中看到 javascript:void(0) 真的让我疯了。 - Tyler McHenry
我更多地是在谈论只影响调用页面的Javascript代码。我也不喜欢看到javascript:void(0) - zneak

5
使用javascript:协议会影响可访问性,并且会降低您的页面的SEO友好度。
请注意,HTML代表超文本某些东西... 超文本表示带有链接和引用的文本,这就是锚点元素<a>的用途。
当您使用javascript:“协议”时,您正在滥用锚元素。由于您滥用了<a>元素,因此像Google Bot和Jaws屏幕阅读器这样的东西将难以“理解”您的页面,因为它们不太关心您的JS,但是对超文本ML非常关注,特别注意锚点hrefs
它还会影响页面的可用性,当没有启用JavaScript的用户访问您的页面时;您正在破坏这些用户的链接的预期功能和行为。它看起来像一个链接,但它不会像一个链接那样工作,因为它使用了javascript协议。
您可能会认为“但现在有多少人禁用JavaScript?”,但我更喜欢将这个想法表达为“我愿意因为浏览器设置中的一个复选框而拒绝多少潜在客户?”
它归结为href是HTML属性,因此它属于您网站的信息,而不是行为。JavaScript定义了行为,但是您永远不希望它干扰数据/信息。这个想法的极致就是外部JavaScript文件;不使用onclick作为属性,而是作为JavaScript文件中的事件处理程序。

这是超文本标记语言。话虽如此,我不同意你信息中的几乎所有内容,除了你的最后一段。因此,我会在另外两条评论中解释原因。 - zneak
就SEO而言,这只是协议处理。我非常确定搜索引擎知道链接是否为HTTP链接,使用未知协议肯定不会使它们出错。我非常确定在我的页面上使用mailto:链接不会使Google讨厌我的页面,仅仅因为它无法跟踪它。 - zneak
1
此外,当一个链接只用于触发脚本时,您始终会误用 <a>,因为您不得不放置一个不相关的 href。在这些情况下,使用 javascript: 协议对禁用Javascript的用户代理更加友好,它只会什么也不做,而不是返回页面顶部,假设不相关但必要的锚点是 #。(这显然假设该链接仅触发Javascript操作而无其他作用。) - zneak
@zneak - 我知道ML代表什么;“某事某事”是为了在我的回答范围内强调HT才加的 ;) 人们往往更关注ML而不是HT。至于SEO,你是对的;Google不会“讨厌”你的页面,但它也不会“喜欢”它;你只是给它一些它可以丢弃的信息。何必呢?至于你关于友好性的论点,我也会连锁评论! - Richard JP Le Guen
我很抱歉有点严厉,但使用 javascript: 协议似乎是一种“懒惰”的方式,在没有 JS 的情况下实现这种友好性。我也觉得你非常强烈地依赖于使用带有 href<a> 元素作为用户应该点击的元素,并因此认为用户会在该元素上看到一个指向手指的光标。因此,如果没有 JS 的用户将鼠标悬停在您的元素上,看到指向手指,认为“我可以与之交互”,然后单击它,但什么也不会发生... - Richard JP Le Guen
如果你担心跳转问题,可以移除 href 并将 cursor:pointer CSS 属性指向该元素。这样,你的锚点就不会去任何地方(比如页面顶部),但仍然有一个指向性的手指。当 JS 失效时,用户点击锚点时不会跳转或者执行其他操作。更好的做法是,在外部 JS 中定义 onclick 时,将 class 属性应用于该元素,并将 cursor 属性指向该属性,这样没有 JS 的用户就没有理由去点击它了!(除了“点击这里”这几个字,哈哈哈) - Richard JP Le Guen

4
最糟糕的问题可能是它破坏了预期的功能。例如,如其他人所指出的,打开新窗口/选项卡 = 坏链接 = 使用户感到恼怒/困惑。
我总是尝试使用 onclick,同时向页面 URL 的哈希添加一些内容以指示要触发的所需功能,并在页面加载时添加一个检查来检查哈希并触发该函数。
这样,您可以获得相同的点击行为、新选项卡/窗口和甚至书签/发送的链接,并且如果 JS 关闭,事情也不会变得太疯狂。
换句话说,类似于这样(非常简化版):
对于链接:
onclick = "doStuff()"

href = "#dostuff"

对于这个页面:

onLoad = if(hash="dostuff") doStuff();

4
简短回答:内联Javascript的坏处与内联CSS的坏处相同。

3

通常我会有一个名为“EnableJavascript.htm”的登陆页面,上面有一条大信息:“此功能需要启用Javascript才能正常工作”。然后我会像这样设置我的锚点标签...

<a href="EnableJavascript.htm" onclick="funcName(); return false;">

这样,锚点就有了一个合法的目标。只要可能,您的JavaScript功能就会覆盖它。这将会优雅地降级。尽管如此,现在我通常会在添加Javascript之前先构建具有完整功能的网站,从而消除对这些锚点的需求。

直接在标记中使用onclick属性是另一个话题,但我建议使用像jQuery这样的库进行非侵入式的处理。


2
此外,既然我们在谈论弃用和语义,那么值得指出的是,'</a>'并不意味着可点击 - 它意味着“锚点”,并暗示着链接到另一个页面。因此,在应用程序中切换到不同的“视图”时使用该标记是有意义的,但不适合执行计算。您没有在href属性中使用URL的事实应该表明您不应该使用锚标记。
您也可以将单击事件操作分配给几乎任何html元素 - 也许<h1><img><p>更合适?无论如何,正如其他人所提到的,添加另一个属性(例如“id”),JavaScript可以使用它作为“钩子”(document.getElementById)来获取元素并分配一个onclick。这样,您可以保持内容(HTML)演示文稿(CSS)和交互性(JavaScript)分离。世界也不会毁灭。

也许使用<span>标签比使用<h1>更合适,因为它在语义上没有意义。但我明白你的意思。 - zneak

1

我认为这与用户在状态栏中看到的内容有关。通常情况下,应该构建应用程序以进行故障转移,以防JavaScript未启用,但并非总是如此。

随着垃圾邮件的不断增加,人们变得越来越聪明,当电子邮件看起来很“可疑”时,越来越多的人会查看状态栏,以查看链接实际上将带他们去哪里。

请记住,在链接末尾添加'return false;',以便页面不会跳到用户的顶部(除非这是您要寻找的行为)。


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