Chrome中SVG <use>元素触发目标mouseenter事件,其他事件不触发的解决方法
问题解决:阻止SVG
问题描述
嵌入的SVG内的元素A绑定了mouseenter、mouseleave、click等事件,当使用<use>元素引用该元素A时,在Chrome及Chromium系浏览器中,<use>会触发A的mouseenter事件,但mouseleave、click等事件却不会触发。由于<use>在页面中可能有完全不同的语义,需要阻止这种事件触发行为,同时保留<use>同步原元素修改、动态重定向的特性,避免克隆元素的方案。
演示示例
HTML代码
<html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GUI</title> </head> <body style=""> <div id="gui"> <svg height="500" version="1.1" width="500" xmlns="http://www.w3.org/2000/svg"> <ellipse cx="100" cy="100" rx="50" ry="50" id="circ"></ellipse> <use href="#circ" x="200"></use> </svg> </div> </body></html>
JavaScript代码
let circle = document.getElementById("circ"); circle.addEventListener("mouseenter",()=>{ // 当鼠标移到<use>上时会触发 circle.setAttribute("fill", "red") }); circle.addEventListener("mouseleave",()=>{ // 不会触发 circle.setAttribute("fill", "black") }); circle.addEventListener("click",()=>{ // 不会触发 circle.setAttribute("fill", "green") });
解决方案
核心思路是在事件回调中,通过composedPath()方法获取事件的传播路径,判断事件是否来自<use>创建的影子DOM实例,若是则终止事件处理。
修改后的JavaScript代码如下:
let circle = document.getElementById("circ"); // 通用判断函数:检查事件是否来自<use>的引用实例 function isFromUseElement(event) { const path = event.composedPath(); // 遍历路径,查找是否存在<use>元素或者影子DOM中的节点 return path.some(node => { return node.tagName === 'USE' || (node.getRootNode && node.getRootNode().host?.tagName === 'USE'); }); } circle.addEventListener("mouseenter",(event)=>{ if (isFromUseElement(event)) return; // 来自<use>则不执行 circle.setAttribute("fill", "red") }); circle.addEventListener("mouseleave",(event)=>{ if (isFromUseElement(event)) return; circle.setAttribute("fill", "black") }); circle.addEventListener("click",(event)=>{ if (isFromUseElement(event)) return; circle.setAttribute("fill", "green") });
原理说明
composedPath()会返回事件传播经过的所有节点,包括影子DOM内的节点。- 对于
<use>创建的实例,事件路径中要么直接包含<use>元素,要么影子DOM节点的宿主(host)是<use>元素,通过这个特征可以判断事件来源。 - 这种方法不需要克隆元素,完全保留
<use>同步原元素修改、动态切换引用的特性。
内容的提问来源于stack exchange,提问作者Vakarelov
相关产品推荐
相关产品推荐

