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

时间:2017-01-13 22:47:07

标签: javascript dom svg

我知道可以将普通的Javascript事件处理程序附加到SVG标记中的元素。我希望复制很多对象的实例,所以我打算使用<def><use>标签来简化一些事情。但是,我的每个孩子的物品都需要处理&#34;点击&#34;和其他事件。我可以为每个孩子定义那些事件,但如果我能以某种方式在初始项目中定义它们,那么这将是很好的,然后只需重复使用&#34;点击事件。这可能吗?

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。

1 个答案:

答案 0 :(得分:1)

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

因此,这意味着原始节点上附加的事件不会被复制到副本,除非此事件是节点标记的一部分(内联)。但是Chrome并没有真正遵循这里的规格,甚至没有让它成功......所以这里是FF的一个例子:

&#13;
&#13;
// this won't work
document.getElementById('someDef').addEventListener('click', function() {
  this.setAttribute('stroke', randomColor());
});
&#13;
<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>
&#13;
&#13;
&#13;

你当然可以通过监听root svg元素上的click事件来使用事件委托,但是这只适用于直接目标元素,而不适用于嵌套目标元素:

&#13;
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;  或者您也可以为每个元素添加一个事件,但这与委托...

具有相同的限制
相关问题