【问题标题】:Animate reused svg independently动画独立重用svg
【发布时间】:2021-03-13 17:45:11
【问题描述】:

我希望一些 SVG 在点击时生成动画。 SVG 被定义一次,并通过<use> 标签多次重复使用。 我写了以下代码:

svg {
  border: 1px solid #0af;
  stroke: black;
}
<svg display="none">
    <symbol id="tick" viewBox="0 0 100 100">
        <polyline points="15,50 40,75 85,25" style="stroke-width:10; fill:none; stroke-linecap:round; stroke-linejoin:round;" stroke-dasharray="120">
            <animate attributeName="stroke-dashoffset" from="120" to="0" dur="0.5s" fill="freeze" repeatCount="1" begin="click" />
        </polyline>
    </symbol>
</svg>

<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>
<svg><use href="#tick"/></svg>

问题是,如果我单击一个 SVG,该 SVG 的所有实例都会被动画化,这不是我想要的。我希望他们独立制作动画。除了多次嵌入完整的 SVG 之外,最好的方法是什么?

【问题讨论】:

  • 多次嵌入完整的 SVG 有什么问题,尤其是考虑到这样做的方法?
  • 在 Firefox 中运行良好,可能是一些 Chrome 错误。如果您不想复制 svg,可以尝试使用一些 svg 动画库。
  • 你是对的@Winns。我在所有主流浏览器中都试过这个,其中只有 Firefox 独立播放动画。在我看来,Firefox 的实现方式与标准不同。
  • @winns 不,Firefox 坏了。
  • SVG2 UseEventHandling:在引用图形中的元素上定义的任何事件侦听器还必须在相同的捕获阶段,在使用元素阴影树中该元素的每个实例上侦听相同的事件. .....用户代理必须确保每个元素实例的事件监听器列表同步以匹配其对应的元素。

标签: javascript html css svg


【解决方案1】:

您可以将您的svg 放在一个文件中,然后在文档树中访问它,如下所示:

<object data="tick.svg"></object>

【讨论】:

    【解决方案2】:

    您的问题是重复 ID

    创建一个 Web 组件(所有现代浏览器都支持)注入您的一旦定义 SVG

    <svg-tick id=ONE stroke="red"></svg-tick>
    <svg-tick id=TWO></svg-tick>
    <svg-tick id=THREE></svg-tick>
    <svg-tick id=FOUR stroke="blue"></svg-tick>
    

    您可以添加更多 Web 组件的好东西,例如属性和单击处理程序...

    我将折线改为path,使用pathLength=100 更容易,无需计算

    id 不是必需的,您也可以使用"ID"+new Date()/1 生成唯一值

    <style>
      svg {
        border: 1px solid #0af;
        stroke: green;
        width: 120px;
        cursor:pointer;
      }
      #TWO svg { stroke: goldenrod;   }
    </style>
    
    <svg-tick id=ONE stroke="red"></svg-tick>
    <svg-tick id=TWO></svg-tick>
    <svg-tick id=THREE></svg-tick>
    <svg-tick id=FOUR stroke="blue"></svg-tick>
    <script>
      customElements.define('svg-tick', class extends HTMLElement {
        connectedCallback() {
          let id = this.id;
          let stroke = this.hasAttribute("stroke") 
                            ? ` stroke=${this.getAttribute("stroke")} ` 
                            : "";
          this.innerHTML = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
        <path id="${id}" d="M15,50 40,75 85,25" pathLength="100" 
            stroke-width="10" fill="none" stroke-linecap="round" stroke-linejoin="round" 
            stroke-dasharray="100" ${stroke}/>
        <animate id="${id}" attributeName="stroke-dashoffset" from="100" to="0" 
               dur="0.5s" fill="freeze" repeatCount="1" begin="click" />
    </svg>`;
          this.onclick = (evt) => console.log('clicked',id);
        }
      });
    </script>

    【讨论】:

    • 非常感谢!自定义 Web 组件方法是解决此问题的好方法。没有黑客攻击,也没有更多的跨浏览器。供您参考,您不一定需要唯一的 ID。您可以在自定义组件内的阴影树下添加所有内容,不会有冲突。
    • 没错,shadowDOM 封装了,但全局 CSS 将不再应用,除非您使用 CSS 属性、::parts 等。
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 2018-09-28
    • 2017-10-06
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多