Vínculos con SVG en línea, mantenerse en el objetivo con eventos | Programar Plus

Es bastante común usar SVG dentro de un enlace de anclaje o “hacer clic / hacer clic” en una página web. También es cada vez más común que el SVG esté en línea <svg>, porque a menudo es bueno tener el SVG en el DOM, ya que puede diseñarlo con CSS y escribirlo con JS y demás. Pero, ¿qué significa eso para los eventos de clic?

Un enlace con un icono SVG podría ser así:

<a href="https://css-tricks.com/links-inline-svg-staying-target-events/#0" data-data="something">
  <svg ... >
     <rect ...>
  <svg>
</a>

Ahora desea vincular un evento de clic a ese enlace de anclaje. En jQuery:

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

});

Eso funcionará perfectamente bien. Tenga en cuenta que hay un data-* atributo en el enlace de anclaje. Probablemente esté ahí específicamente para que JavaScript acceda y use. No hay problema en absoluto en cómo lo tenemos escrito en este momento, porque dentro de la función anónima hemos vinculado, this siempre será ese enlace de anclaje, que tiene ese atributo disponible. Incluso si usa la delegación de eventos y llama a alguna función quién sabe dónde manejarla, this será ese enlace de anclaje y puede engancharlo fácilmente data-* atributo.

Pero digamos que vas a sacudir alguna delegación de eventos de JavaScript sin procesar:

document.addEventListener('click', doThing);

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

No tiene una referencia fácil a su enlace de anclaje allí. Deberá probar event.target para ver si incluso es el enlace de anclaje. Pero en el caso de nuestro SVG-in-a-link, ¿cuál es ese objetivo?

Podría ser:

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

Es posible que solo tenga que verificar el tagName del elemento en el que se hizo clic, y si sabe que era un subelemento, suba en la cadena:

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"));
}

Aunque eso es bastante loco. Está demasiado ligado a la estructura HTML y SVG. Lanzar un <g> allí alrededor de algunos <path>s, que está perfectamente bien para agrupar, y se rompe. O la tagType es path No un rect, o cualquier otra diferencia DOM.

Personalmente, he preferido algunas soluciones CSS.

Una forma es colocar un pseudo elemento encima de todo el elemento de anclaje, de modo que se garantice que los clics estarán en el elemento de anclaje en sí, nada dentro de él:

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

Esto también parece funcionar bastante bien:

a > svg {
  pointer-events: none;
}

pointer-events normalmente no funciona en IE (lo hace en 11+, pero no en una versión inferior), pero en realidad lo hace cuando se aplica a SVG, en IE 9+, que es la versión de IE que admite SVG de todos modos.

Aquí hay un bolígrafo con el problema demostrado y las correcciones:

Vea el Pen owyFj de Chris Coyier (@chriscoyier) en CodePen.

El punto es

Si está utilizando SVG en un destino de clic, tenga mucho cuidado de obtener el elemento correcto en JavaScript y, si tiene problemas, considere una cubierta de CSS.

(Visited 3 times, 1 visits today)