在锚点上执行 Javascript 的最佳方式

发布于 2024-12-05 20:15:37 字数 727 浏览 0 评论 0原文

一般来说,有 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

爱已欠费 2024-12-12 20:15:37

如果您通过 ajax 加载内容并需要连接事件处理程序,那么您有以下选择:

  1. 使用选项 1) 或 2) 将 javascript 处理程序放入 HTML 中。在我看来,选项 1) 是一种更清晰的指定方式,但我不认为 1) 或 2) 之间有很大的差异 - 它们本质上都是做同样的事情。一般来说,我不喜欢这个选项,因为我认为将标记和代码分开是有价值的。
  2. 使用ajax加载内容后,调用一些本地代码来查找并连接所有链接。如果页面中的 HTML 是静态 HTML,这将与您页面中的代码类型相同,并在 DOMReady 上执行。我将使用 addEventListener (回退到 AttachEvent)来连接这种方式,因为它更干净地允许单个对象的多个侦听器。
  3. 在使用 ajax 加载内容后调用一些代码,该代码会查找所有链接并将点击连接到某个通用点击处理程序,然后该处理程序可以检查链接中的元数据并根据元数据确定应在该点击上执行哪些操作。例如,此元数据可以是单击的链接上的属性。
  4. 当您加载内容时,还加载可以单独查找每个链接的代码,并为每个链接连接适当的事件处理程序,就像在常规页面中加载内容一样。这将满足将 HTML 与 JS 分离的愿望,因为 JS 会找到每个适当的链接并使用 addEventListener 或 AttachEvent 为其连接一个事件处理程序。
  5. 与 jQuery .live() 的工作方式非常相似,为文档级别的链接上未处理的点击连接一个通用事件处理程序,并根据链接中的某些元数据分派每次点击。
  6. 运行一些使用实际框架(如 jQuery 的 .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:

  1. Put a javascript handler in your HTML with your option 1) or 2). In my mind option 1) is a cleaner way of specifying it, but I don't think there's a mountain of difference between 1) or 2) - they both do essentially the same thing. I'm not a fan of this option in general because I think there's value in keeping the markup and the code separate.
  2. After loading the content with ajax, call some local code that will find and hook up all the links. This would be the same kind of code you would have in your page and execute on DOMReady if the HTML had been static HTML in your page. I would use addEventListener (falling back to attachEvent) to hook up this way as it more cleanly allows multiple listeners for a single object.
  3. Call some code after you load the content with ajax that finds all the links and hooks up the clicks to some generic click handler that can then examine meta data in the link and figure out what should be done on that click based on the meta data. For example, this meta data could be attributes on the clicked link.
  4. When you load the content, also load code that can find each link individually and hook up an appropriate event handler for each link much the way one would do it if the content was just being loaded in a regular page. This would meet the desire of separating HTML from JS as the JS would find each appropriate link and hook up an event handler for it with addEventListener or attachEvent.
  5. Much like jQuery .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.
  6. Run some code that uses an actual framework like jQuery's .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.

疯狂的代价 2024-12-12 20:15:37

现代浏览器支持内容安全策略或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.

指尖上得阳光 2024-12-12 20:15:37

我坚信将 javascript 与标记分开。恕我直言,用于显示目的和用于执行目的之间应该有明显的区别。话虽如此,请避免使用 onclick 属性并在 href 属性中嵌入 javascript:*

替代品?

  1. 您可以使用 AJAX 包含 javascript 库文件。
  2. 您可以设置 javascript 来查找 DOM 中的更改(即,如果它是“标准任务”,则使锚点使用 CSS 类名称,该名称可用于在稍后动态添加时绑定特定机制。(jQuery 做得很好)在此使用 .delegate()))
  3. 运行脚本 POST-AJAX 调用。 (引入新内容,然后使用 javascript 来[重新]绑定功能)例如:
function ajaxCallback(content){
  // add content to dom
  // search within newly added content for elements that need binding
}

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 embedding javascript:* in a href attribute.

Alternatives?

  1. You can include javascript library files using AJAX.
  2. You can setup javascript to look for changes in the DOM (i.e. if it's a "standard task", make the anchor use a CSS class name that can be used to bind a specific mechanism when it's later added dynamically. (jQuery does a great job at this with .delegate()))
  3. Run your scripts POST-AJAX call. (Bring in the new content, then use javascript to [re]bind the functionality) e.g.:
function ajaxCallback(content){
  // add content to dom
  // search within newly added content for elements that need binding
}
情话已封尘 2024-12-12 20:15:37

如果您想通过 AJAX 加载,则第 3 号并不是“out”。

var link = document.createElement("a");
//Add attributes (href, text, etc...)
link.onclick = function () { //This has to be a function, not a string
    //Handle the click
    return false; //to prevent following the link
};
parent.appendChild(link); //Add it to the DOM

Number 3 is not "out" if you want to load via AJAX.

var link = document.createElement("a");
//Add attributes (href, text, etc...)
link.onclick = function () { //This has to be a function, not a string
    //Handle the click
    return false; //to prevent following the link
};
parent.appendChild(link); //Add it to the DOM
緦唸λ蓇 2024-12-12 20:15:37

其他答案已经解决了安全性以及分离标记和代码的方面,但我认为一方面有更多关于在 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 using addEventListener). 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, if href 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 any href 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 same href="#" 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 use history.pushState (see MDN ) instead of replaceState (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 ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文