在锚点上执行 Javascript 的最佳方式
一般来说,有 3 种方法(据我所知)可以从 标签执行 javascript:
1) 使用 onclick()
:
<a href="#" onclick="alert('hello'); return false">hello</a>
2) 直接链接:
<a href="javascript:alert('hello')">hello</a>
3)或者从外部附加:
// In an onload event or similar
document.getElementById('hello').onclick = window.alert('Hello');
return false;
<a id="hello" href="#">hello</a>
我实际上是通过AJAX加载链接,所以#3基本上已经出局了。那么,是做#1 更好,还是做#2 更好,还是做一些完全不同的事情?还有,为什么?我应该注意哪些陷阱?
另外值得注意的是,锚点实际上没有链接到任何地方,因此 href="#"
,我使用 a
因此样式符合,因为这仍然是一个对象被点击并且按钮在上下文中不合适。
谢谢
Generally, there are 3 ways (that I am aware of) to execute javascript from an <a/>
tag:
1) Use onclick()
:
<a href="#" onclick="alert('hello'); return false">hello</a>
2) Directly link:
<a href="javascript:alert('hello')">hello</a>
3) Or attach externally:
// In an onload event or similar
document.getElementById('hello').onclick = window.alert('Hello');
return false;
<a id="hello" href="#">hello</a>
I am actually loading the link via AJAX, so #3 is basically out. So, is it better to do #1 or #2 or something completely different? Also, why? What are the pitfalls that I should be aware of?
Also of note, the anchor really doesn't link anywhere, hence the href="#"
, I am using a
so the styles conform as this is still an object to be clicked and a button is inappropriate in the context.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您通过 ajax 加载内容并需要连接事件处理程序,那么您有以下选择:
.live()
的工作方式非常相似,为文档级别的链接上未处理的点击连接一个通用事件处理程序,并根据链接中的某些元数据分派每次点击。.live()
功能)的代码,而不是构建您自己的功能。我会使用哪个将取决于具体情况。
首先,在附加事件处理程序的三个选项中,我将使用新选项 #4。我会使用 addEventListener (对于旧版本的 IE,回退到 AttachEvent)而不是分配给 onclick,因为这更干净地允许一个项目上有多个侦听器。如果是我,我会使用一个框架(jQuery 或 YUI),使跨浏览器兼容性不可见。这允许 HTML 和 JS 完全分离(没有 JS 与 HTML 内联),我认为这在任何涉及多人的项目中都是可取的,而且对我来说似乎更干净。
然后,这对我来说只是一个问题,选择哪一个选项上面我将用来运行连接这些事件侦听器的代码。
如果我动态加载有很多不同的 HTML 片段,并且如果它们都是“独立的”并且可单独维护,那么我会希望同时加载 HTML 和相关代码,这样就会更干净加载的代码句柄连接到适当的链接。
如果不是真正需要通用的独立系统,因为只需要加载几个片段,并且处理它们的代码可以预先包含在页面中,那么我可能只需在 HTML 片段加载后进行函数调用即可。通过 ajax 加载,使 javascript 连接到刚刚加载的代码片段中的链接。这将保持 HTML 和 JS 之间的完全分离,但非常容易实现。您可以在每个片段中放置某种关键对象,该对象将识别要调用的 JS 片段,或者可以用作传递给 JS 的参数,或者 JS 可以检查片段以查看哪些对象可用并连接到无论哪一个在场。
If you are loading the content via ajax and need to hook up event handlers, then you have these choices:
.live()
works, hook up a generic event handler for unhandled clicks on links at the document level and dispatch each click based on some meta data in the link..live()
capability rather than building your own capability.Which I would use would depend a little on the circumstances.
First of all, of your three options for attaching an event handler, I'd use a new option #4. I'd use addEventListener (falling back to attachEvent for old versions of IE) rather than assigning to onclick because this more cleanly allows for multiple listeners on an item. If it were me, I'd be using a framework (jQuery or YUI) that makes the cross browser compatibility invisible. This allows complete separation of HTML and JS (no JS inline with the HTML) which I think is desirable in any project involving more than one person and just seems cleaner to me..
Then, it's just a question for me for which of the options above I'd use to run the code that hooks up these event listeners.
If there were a lot of different snippets of HTML that I was dynamically loading and it would be cleaner if they were all "standalone" and separately maintainable, then I would want to load both HTML and relevant code at the same time so have the newly loaded code handle hooking up to it's appropriate links.
If a generic standalone system wasn't really required because there were only a few snippets to be loaded and the code to handle them could be pre-included in the page, then I'd probably just make a function call after the HTML snippet was loaded via ajax to have the javascript hook up to the links in the snippet that had just been loaded. This would maintain the complete separation between HTML and JS, but be pretty easy to implement. You could put some sort of key object in each snippet that would identify which piece of JS to call or could be used as a parameter to pass to the JS or the JS could just examine the snippet to see which objects were available and hook up to whichever ones were present.
现代浏览器支持内容安全策略或CSP。这是网络安全的最高级别,强烈建议您应用它,因为它完全阻止所有 XSS 攻击。
CSP 执行此操作的方式是禁用用户可以将 Javascript 注入页面的所有向量 - 在您的问题中,即选项 1 和 2(尤其是 1)。
因此,最佳实践始终是选项 3,因为如果启用 CSP,任何其他选项都会中断。
Modern browsers support a Content Security Policy or CSP. This is the highest level of web security and strongly recommended if you can apply it because it completely blocks all XSS attacks.
The way that CSP does this is disabling all the vectors where a user could inject Javascript into a page - in your question that is both options 1 and 2 (especially 1).
For this reason best practice is always option 3, as any other option will break if CSP is enabled.
我坚信将 javascript 与标记分开。恕我直言,用于显示目的和用于执行目的之间应该有明显的区别。话虽如此,请避免使用
onclick
属性并在href
属性中嵌入javascript:*
。替代品?
.delegate()
))I'm a firm believer of separating javascript from markup. There should be a distinct difference, IMHO, between what is for display purposes and what is for execution purposes. With that said, avoid using
onclick
attribute and embeddingjavascript:*
in ahref
attribute.Alternatives?
.delegate()
))如果您想通过 AJAX 加载,则第 3 号并不是“out”。
Number 3 is not "out" if you want to load via AJAX.
其他答案已经解决了安全性以及分离标记和代码的方面,但我认为一方面有更多关于在
href
属性中指定 javascript 函数之间的差异(选项 2 ),另一方面将其附加为事件处理程序(选项 1 或 3 或使用addEventListener
)。了解这些差异肯定有助于根据用例和个人喜好选择方法。不同的会话历史记录
单击具有指定
href
属性的锚标记通常会向浏览器会话历史记录添加一个条目。但是,如果href
的类型为"javascript:..."
(选项 2),情况似乎并非如此。单击后链接的外观保持“未访问”状态(我在规范中的任何地方都没有找到这一点,但这是 Chrome 110 和 Firefox 110 的当前行为),并且使用 browser-back 转到历史记录中已经存在的任何页面单击之前。这可能是想要的行为,具体取决于用例。如果 href 的类型为
"#"
(选项 1 和 3),则这是一个有效的相对 URL,并将在浏览器历史记录中添加一个条目。点击后会显示“已访问”,浏览器历史记录多了一个条目。正如问题中提到的,使用"#"
的原因是,如果没有任何href
属性,浏览器不会将元素设置为链接样式。相对主题标签链接或 URI 片段 不会引发对服务器的请求,而是跨域的仅网页内的链接(指向片段中指定其 id 的 html 元素,或者 - 如果片段像这里一样为空 - 指向完整文档)。但是,如果对多个 javascript 链接使用相同的href="#"
,那么应该考虑到,在仅单击其中一个链接后,所有这些链接都会显示为“已访问”链接。因此,人们可能想为每个人使用唯一的主题标签。根据用例,这可以与 URI 片段的真实含义保持一致。例如,如果 javascript 函数在某个 html 元素内绘制图表,则可以使用该元素的 id,以便浏览器将滚动到那里。人们还可以使用根本不存在的主题标签作为页面上的 id(因此无法滚动),但这是对 URI 片段的轻微滥用。附加历史记录仅包含 URL(具有不同的片段),但不包含有关 javascript 调用的信息。可以使用历史 API(例如history.replaceState
- 请参阅 MDN)向历史条目添加更多信息,这样(如果需要)浏览历史记录时也可以恢复 javascript 调用后网页的完整状态到此条目。相反,对于选项 2,为了实现相同的效果,需要使用history.pushState
(请参阅 MDN )而不是replaceState
(因为在这种情况下没有自动添加历史条目)事件无障碍
问题选项之间的另一个区别是,当使用事件处理程序时,可以访问事件,并且可以检查哪个鼠标按钮用于单击或是否按下了某个附加键(shiftKey、ctrlKey、altKey、元密钥)。对于方法 2 来说这是不可能的,或者只有添加一个额外的单击处理程序来存储信息并使其可供在
href
属性中调用的函数访问时才能实现这一点...Other answers have already addressed the aspects of security and of separating markup and code, but I think there is more to say about the differences between specifying the javascript function in the
href
attribute on the one hand (option 2) and attaching it as an event-handler on the other hand (options 1 or 3 or usingaddEventListener
). And knowing these differences will certainly help choosing the approach depending on the use case and on personal preference.different session history
Clicking an anchor tag with a specified
href
attribute usually adds an entry to the browser session history. However, ifhref
is of type"javascript:..."
(option 2) this does not seem to be the case. The appearance of the link remains "unvisited" after clicking (I haven't found this anywhere in the specs, but it is the current behavior of Chrome 110 and Firefox 110) and using browser-back goes to whatever page was in the history already before clicking. This might be wanted behavior, depending on the use case.If instead href is of type
"#"
(options 1 and 3), this is a valid relative url and adds an entry to the browser history. After clicking it, it will appear "visited" and the browser history has an additional entry. As mentioned in the question, the reason for using"#"
is that without anyhref
attribute, the browser will not style the element as a link. And relative hashtag links or URI fragments do not induce a request to the server, but are cross-links within the webpage only (pointing to an html-element with its id specified in the fragment or - if the fragment is empty like here - to the complete document). But if one uses the samehref="#"
for several javascript-links, then one should take into account that all of them will appear as "visited" links after clicking only one of them. So one might want to use instead unique hashtags for each of them. Depending on the use case this can be made consistent with the true meaning of the URI-fragment. E.g. if the javascript function draws a chart within a certain html-element, one could use the id of this element, so that the browser will scroll there. One can also use hashtags that simply don't exist as id's on the page (so no scrolling), but this is a slight abuse of the URI fragment. The additional history-entry contains only the URL (with different fragment), but no information about the javascript-call. One can use the history-API (e.g.history.replaceState
- see MDN) to add more information to the history-entry, such that (if wanted) the full state of the web-page after the javascript-call could also be restored when browsing the history to this entry. In contrast, for option 2, in order to achieve the same, one would need to usehistory.pushState
(see MDN ) instead ofreplaceState
(as there is no history entry added automatically in this case)event accessibility
An additional difference between the options of the question is, that when using event handlers, one has access to the event and can e.g. check which mouse-button was used for the click or if some additional key was pressed (shiftKey, ctrlKey, altKey, metaKey). This is not possible with the approach 2, or only if one adds an additional click handler which stores the information and makes it accessible for the function that is called in the
href
attribute ...