当事件目标为HTMLImageElement时,如何获取锚点的href?

17

当单击锚元素时,我想要获取它的href。 我正在使用以下JavaScript代码:

document.addEventListener('click', function (event)
{
    event = event || window.event;
    var el = event.target || event.srcElement;

    if (el instanceof HTMLAnchorElement)
    {
        console.log(el.getAttribute('href'));
    }
}, true);

这对于像这样的嵌入式锚点完美地起作用:

<div><p><a href='link'></a></p><div>

但是当我同时使用锚点和图片时,它不起作用:

<div><a href='link'><img></a></div>

event.target 返回图片而不是链接。可以通过下面的 if 语句来修改 JavaScript 代码以解决这个问题:

document.addEventListener('click', function (event)
{
    event = event || window.event;
    var el = event.target || event.srcElement;

    if (el instanceof HTMLImageElement)
    {
        // Using parentNode to get the image element parent - the anchor element.
        console.log(el.parentNode.getAttribute('href'));
    }
    else if (el instanceof HTMLAnchorElement)
    {
        console.log(el.getAttribute('href'));
    }
}, true);

但这似乎并不太优雅,我想知道是否有更好的方法。

!重要说明! 注意:请记住,我无法访问ID、类或任何其他传统标识符。 我只知道将单击锚定并需要获取其href。 我甚至不知道它在哪里,如果存在或稍后会创建。

编辑:请不要使用jQuery或其他JavaScript库。


你正在寻找.currentTarget或者简单地使用this,它将会指向安装处理程序的元素而不是被点击的元素。 - Bergi
.currentTargetthis都是document元素,因为事件监听器在其上使用。 - Aurelije Aure
啊,我没注意到你使用了全局处理程序。 - Bergi
2个回答

37

不要在DOM中循环所有锚点,而是从event.target元素查找。
使用JavaScript的.closest() MDN文档

addEventListener('click', function (event) {
  event.preventDefault();                     // Don't navigate!
  const anchor = event.target.closest("a");   // Find closest Anchor (or self)
  if (!anchor) return;                        // Not found. Exit here.
  console.log( anchor.getAttribute('href'));  // Log to test
});
<a href="https://dev59.com/tl4b5IYBdhLWcg3wYQmZ#29223576">
  <span>
      <img src="//placehold.it/200x60?text=Click+me">  
  </span>
</a>

<a href="https://dev59.com/tl4b5IYBdhLWcg3wYQmZ#29223576">
  Or click me
</a>

它的工作方式基本上类似于jQuery的.closest()函数,即查找最近的父元素...否则就是目标元素本身!以上例子更好地说明了这一点。

这是一个非常好的解决方案。它比我的解决方案更具有未来性和可维护性。然而,它在浏览器支持方面非常糟糕。 :( - Aurelije Aure
@AurelijeAure 我喜欢推动互联网的发展,因此我预计在不久的将来会有很多人使用这种方法,因为这种方法是一种尚未被所有供应商采用的生活标准。 - Roko C. Buljan
现在我想起来,如果页面上存在锚点,那么这个解决方案将在每次单击时获取一个href,因为它会继续解析DOM直到找到一个。 - Aurelije Aure
@AurelijeAure 是的,因为它使用了 document - 相反地,使用 Array.from 传递 document.querySelectorAll('a') 并将监听器添加到每个 Anchor 元素。为确保它真的有一个 href,您可以使用属性选择器 document.querySelectorAll('a[href]') - Roko C. Buljan
真是一个很好的解决方案。event.target.href给了我undefined。 - Shamsul Arefin

23

与其添加一个全局的 click 处理程序,为什么不只针对锚点标签进行操作呢?

var anchors = document.getElementsByTagName("a");
for (var i = 0, length = anchors.length; i < length; i++) {
  var anchor = anchors[i];
  anchor.addEventListener('click', function() {
    // `this` refers to the anchor tag that's been clicked
    console.log(this.getAttribute('href'));
  }, true);
};

如果你想坚持使用文档范围内的点击处理程序,那么你可以向上遍历来确定被点击的元素是否是链接本身或包含在链接中,像这样:

document.addEventListener('click', function(event) {
    event = event || window.event;
    var target = event.target || event.srcElement;

    while (target) {
      if (target instanceof HTMLAnchorElement) {
        console.log(target.getAttribute('href'));
        break;
      }

      target = target.parentNode;
    }
}, true);

通过这种方式,您至少可以避免编写脆弱的代码,该代码必须考虑所有可能的锚点子级和嵌套结构。


1
刚刚在写同样的答案,这是正确的方法。 - Etheryte
我已经考虑过这个问题,但我在想页面上的锚点数量是否会使循环成为一个不必要的性能问题。更不用说所有产生的JavaScript代码了。此外,正如我在注释中所解释的那样,我不知道带有锚点的元素是否存在,而你的解决方案假设它存在。虽然有一些变通方法,但它们并不美观。 - Aurelije Aure
这真是一段优秀的代码!虽然不是我所期望的乌托邦式解决方案,但它能够工作。谢谢。 - Aurelije Aure

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