内联 SVG 的链接,使用事件保持目标

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

在网页上,使用 SVG 作为锚链接或其他“可点击/可触摸元素”是很常见的。内联 <svg> 也越来越普遍,因为将 SVG 放置在 DOM 中通常很方便,因为您可以使用 CSS 对其进行样式设置,并使用 JS 对其进行脚本处理等等。但这对点击事件意味着什么呢?

包含 SVG 图标的链接可能如下所示

<a href="#0" data-data="something">
  <svg ... >
     <rect ...>
  <svg>
</a>

现在您想将点击事件绑定到该锚链接。在 jQuery 中

$("a").on("click", function(event) {
  
   // `this` will always be the <a>
  console.log($(this).data("data"));
  // "something"

});

这将完美运行。请注意锚链接上有一个 data-* 属性。这可能是专门为 JavaScript 访问和使用而设置的。就我们目前编写的方式而言,完全没有问题,因为在我们绑定的匿名函数中,this 将始终是该锚链接,该链接具有可用的属性。即使您使用事件委托并调用某个未知位置的函数来处理它,this 也会是该锚链接,并且您可以轻松地获取该 data-* 属性。

但是,假设您要使用一些原始的 JavaScript 事件委托

document.addEventListener('click', doThing);

function doThing(event) {
  // test for an element match here
}

您在那里没有对锚链接的简单引用。您需要测试 event.target 以查看它是否确实是锚链接。但在我们的 SVG-in-a-link 的情况下,目标是什么呢?

它可能是

  1. <a>
  2. <svg>
  3. <rect>

您可能只需要检查被点击元素的 tagName,如果知道它是一个子元素,则向上移动链

document.addEventListener('click', doThing);

function doThing(event) {
  var el;
  
  // we can check the tag type, and if it's not the <a>, move up.
  if (event.target.tagType == "rect") {
    // move up TWICE
    el = event.target.parentElement.parentElement;
  } else if (event.target.tagType == "svg") {
    // move up ONCE
    el = event.target.parentElement;
  } else {
    el = event.target;
  }
  console.log(el.getAttribute("data-data"));
}

但这有点疯狂。它与 HTML 和 SVG 结构的绑定太紧密了。在一些 <path> 周围添加一个 <g>,这对于分组来说是一件非常好的事情,但它会破坏它。或者 tagTypepath 而不是 rect,或者任何其他 DOM 差异。

就我个人而言,我更喜欢一些 CSS 解决方案。

一种方法是在整个锚元素的顶部放置一个伪元素,以便点击保证在锚元素本身上,而不是其内部的任何内容

a {
  position: relative;
}
a::after {
  content: "";
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

这似乎也运行良好

a > svg {
  pointer-events: none;
}

pointer-events 通常在 IE 中不起作用(在 11+ 中起作用,但在较低版本中不起作用),但当应用于 SVG 时,它实际上在 IE 9+ 中起作用,而 IE 9+ 是支持 SVG 的 IE 版本。

这是一个展示问题和修复方案的 Pen

查看 Chris Coyier 在 CodePen 上的 Pen owyFj (@chriscoyier)。

重点是

如果在点击目标中使用 SVG,请务必小心在 JavaScript 中获取正确的元素,如果遇到问题,请考虑使用 CSS 覆盖。