javascript - 将 Javascript 事件添加到 SVG <def> 元素而不是直接添加到子元素上?

标签 javascript dom svg

我知道可以将普通的 Javascript 事件处理程序附加到 SVG 标记内的元素。我希望复制一个对象的很多实例,因此我计划使用 <def><use>标签来简化一些事情。然而,我的每个子项目都需要处理“点击”和其他事件。我可以为每个 child 定义这些事件,但如果我能以某种方式在初始项目中定义它们一次,然后“重用”该单击事件,那就太好了。这可能吗?

https://jsfiddle.net/khyp1o0w/

<svg width="400" height="400" viewBox="0 0 400 400">
    <defs>
        <rect id="someDef" x="0" y="0" width="60" height="30" fill="#f00" />  
        <!--  ^^ would like to define an event here... -->
    </defs>

    <use x="150" y="150" xlink:href="#someDef" />
    <use x="250" y="250" xlink:href="#someDef" />  
    <!--  ^^  ... that is used by these guys  -->

</svg>

编辑:添加示例 SVG。

最佳答案

use 元素所针对的 IIRC 元素应在内部复制到 <use> 元素中,就像 <use> 是 iframe 一样,并且内容已被克隆。

因此,这意味着附加在原始节点上的事件不会复制到副本上,除非该事件是节点标记的一部分(内联)。但是 chrome 并没有真正遵循这里的规范,甚至无法使其工作......所以这里是 FF 的示例:

// this won't work
document.getElementById('someDef').addEventListener('click', function() {
  this.setAttribute('stroke', randomColor());
});
<svg width="400" height="400" viewBox="0 0 400 400">
  <defs>
    <script type="application/javascript">
      function randomColor() {
        var letters = '0123456789ABCDEF'.split('');
        var color = '#';
        for (var i = 0; i < 6; i++) {
          color += letters[~~(Math.random() * 15)];
        }
        return color;
      }
    </script>
    <!-- this will work in FF -->
    <rect id="someDef" onclick="this.setAttribute('fill',randomColor())" x="0" y="0" width="60" height="30" fill="#f00" />
  </defs>

  <use x="150" y="150" xlink:href="#someDef" />
  <use x="250" y="250" xlink:href="#someDef" />
</svg>

您当然可以通过监听根 svg 元素上的单击事件来使用事件委托(delegate),但这仅适用于直接目标元素,不适用于嵌套元素:

var svg = document.querySelector('svg');
svg.addEventListener('click', function(e) {
  var usedTargetID = e.target.getAttributeNS("http://www.w3.org/1999/xlink", 'href');
  switch (usedTargetID) {
    case '#direct':
      clickDirect(e);
      break;
    case '#nested':
      clickNested(e);
      break;
    default:
      return;
  }
});

function clickDirect(e) {
  // what you seem to want
  e.target.setAttribute('fill', randomColor());
}

function clickNested(e) {
  // will set both nested...
  e.target.setAttribute('fill', randomColor());
}

function randomColor() {
  var letters = '0123456789ABCDEF'.split('');
  var color = '#';
  for (var i = 0; i < 6; i++) {
    color += letters[~~(Math.random() * 15)];
  }
  return color;
}
<svg width="400" height="400" viewBox="0 0 400 400">
  <defs>
    <rect id="direct" x="0" y="0" width="60" height="30" />
    <g id="nested">
      <!-- you can only access this -->
      <!-- not its content individually -->
      <rect x="80" y="0" width="60" height="30" />
      <rect x="20" y="70" width="60" height="30" />
    </g>

  </defs>

  <use x="150" y="50" xlink:href="#direct" />
  <use x="250" y="150" xlink:href="#nested" />
</svg>
或者,您也可以为每个元素添加一个事件,但这将具有与委托(delegate)相同的限制...

关于javascript - 将 Javascript 事件添加到 SVG <def> 元素而不是直接添加到子元素上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41644645/

相关文章:

javascript - onClick 在我使用它时不起作用

javascript - DOMNodeInserted 在 IE 中的等效项?

javascript - react .createClass() 滚动到 ref : scrollIntoView not a function

javascript - zingchart 数据分组和下采样

javascript - 在 SVG 中使用 HTML 格式进行文本对齐

javascript - 删除 Javascript 数组中的字符串时遇到问题

javascript - 将 jQuery ReplaceWith() 与 HTML Select 一起使用

javascript - Node、Bluebird Promises、MySQL 以及喝一杯烈性酒的必要性

jquery-plugins - Javascript 中的直方图 slider

javascript - Angular + Websockets + 数据渲染