【问题标题】:How to reset an SVG animation?如何重置 SVG 动画?
【发布时间】:2020-08-29 14:32:48
【问题描述】:

const button = document.getElementById('healer')

const preloaded = new Image()
preloaded.src = "https://svgshare.com/i/KzN.svg"

const img = document.getElementById("heal")
//img.style.display = "none"

button.onclick = () => {
    button.disabled = true
    img.src = "https://svgshare.com/i/KzN.svg"
    img.style.display = ""
    setTimeout(() => {
        button.disabled = false
        img.src = ""
        //img.style.display = "none"
    }, 1000)
}
#monster {
  height: 160px;
  width: 160px;
}

#heal {
    height: 160px;
    width: 160px;
    position: absolute;
    top: 0;
    left: 0;
}
<img id="monster" src="https://i.imgur.com/NMocKWy.png">
<img id="heal">

<button id="healer">
    Show heal anim
</button>

如您所见,只有第一次点击会产生动画。后续点击无效。我认为这是因为 SVG 设置为仅运行一次动画 (SVG source code),即使 img 标签的 src 属性设置为空然后再次设置为 SVG,浏览器也不会重置动画(即使根据这个 Stackoverflow 线程重置 src 应该重置动画:Proper way to reset a GIF animation with display:none on Chrome)。

将 SVG 设置为无限运行动画 (modified SVG source code) 只是稍微好一点:

const button = document.getElementById('healer')

const preloaded = new Image()
preloaded.src = "https://svgshare.com/i/L0q.svg"

const img = document.getElementById("heal")
//img.style.display = "none"

button.onclick = () => {
    button.disabled = true
    img.src = "https://svgshare.com/i/L0q.svg"
    img.style.display = ""
    setTimeout(() => {
        button.disabled = false
        img.src = ""
        //img.style.display = "none"
    }, 1000)
}
#monster {
  height: 160px;
  width: 160px;
}

#heal {
    height: 160px;
    width: 160px;
    position: absolute;
    top: 0;
    left: 0;
}
<img id="monster" src="https://i.imgur.com/NMocKWy.png">
<img id="heal">

<button id="healer">
    Show heal anim
</button>

浏览器似乎一直在内部运行动画,所以只有第一次按钮点击是正确的,随后的点击从中间开始动画并在中间结束,我认为这看起来不太理想。

有什么方法可以让这项工作按预期进行吗? (我正在尝试为类似 Pokemon 的基于浏览器的游戏实现治愈动画)

如果我在 HTML 代码中内联 SVG,我想我可以让它工作,因为这可以让我直接访问样式,并重置样式 AFAIK DOES restart the animation,但我发现 HTML 中的内联图形很难看。这样做是我唯一的选择吗?

BTW display: none' 已被注释掉,因为根据链接的 SO 问题,它可能会与动画重置混淆(但对我来说并没有改变任何东西)。预加载对我来说似乎也没有太大变化,但由于 svgshare 的响应速度慢而需要。我在 Firefox、Windows 上。

【问题讨论】:

    标签: javascript html css svg css-animations


    【解决方案1】:

    这确实是一种非常奇怪的行为,但您可以通过附加一个随机的# 片段网址来欺骗它。
    这将强制浏览器重新解析整个文档,但不会再次获取内容,因为它已经被缓存了。

    这是一个仅适用于 Firefox 的示例:

    const button = document.getElementById('healer')
    
    const preloaded = new Image()
    preloaded.src = "https://svgshare.com/i/KzN.svg"
    
    const img = document.getElementById("heal")
    img.style.display = "none"
    
    button.onclick = () => {
        button.disabled = true
        img.src = "https://svgshare.com/i/KzN.svg#" + Math.random();
        img.style.display = ""
        setTimeout(() => {
            button.disabled = false
            img.src = ""
            img.style.display = "none"
        }, 1000)
    }
    #monster {
      height: 160px;
      width: 160px;
    }
    
    #heal {
        height: 160px;
        width: 160px;
        position: absolute;
        top: 0;
        left: 0;
    }
    <img id="monster" src="https://i.imgur.com/NMocKWy.png">
    <img id="heal">
    
    <button id="healer">
        Show heal anim
    </button>

    要使其在 Chrome 中运行,您必须更改 svg 以便在 &lt;use&gt; 元素上设置 animation 而不是 &lt;polygon&gt; 元素:

    // For Chrome we need to fix OP's svg image
    // we will thus create a blob:// URI
    const content = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-80 -80 160 160">
        <style>
            polygon {
                fill: lime;
                stroke: green;
                stroke-width: 4px;
            }
            use {
              animation: linear both moveCross 0.4s var(--delay);
            }
            @keyframes moveCross {
                from {
                    transform: translate(var(--x-off), 99px) scale(1);
                }
                
                to {
                    transform: translate(var(--x-off), 0) scale(0);
                }
            }
        </style>
        
      <defs>
            <polygon id="cross" points="-5,-15, 5,-15, 5,-5, 15,-5, 15,5, 5,5, 5,15, -5,15, -5,5, -15,5, -15,-5, -5,-5"/>
      </defs>
        
        <!-- twice as many crosses for moves stronger than Wait, like Rejuvenate? -->
        
        <use hef="#cross" style="--x-off: -61.0px; --delay: 0.00s;"/>
        <use href="#cross" style="--x-off:  30.5px; --delay: 0.15s;"/>
        <use href="#cross" style="--x-off: -30.5px; --delay: 0.30s;"/>
        <use href="#cross" style="--x-off:  61.0px; --delay: 0.45s;"/>
        <use href="#cross" style="--x-off:   0.0px; --delay: 0.60s;"/>
    </svg>`;
    const blob = new Blob([content], {
      type: "image/svg+xml"
    });
    const url = URL.createObjectURL(blob);
    
    const button = document.getElementById('healer')
    
    const img = document.getElementById("heal")
    img.style.display = "none"
    
    button.onclick = () => {
      button.disabled = true;
      img.src = url + '#' + Math.random();
      img.style.display = ""
      setTimeout(() => {
        button.disabled = false
        img.src = "";
        img.style.display = "none"
      }, 1000)
    }
    #monster {
      height: 160px;
      width: 160px;
    }
    
    #heal {
        height: 160px;
        width: 160px;
        position: absolute;
        top: 0;
        left: 0;
    }
    <img id="monster" src="https://i.imgur.com/NMocKWy.png">
    <img id="heal">
    
    <button id="healer">
        Show heal anim
    </button>

    【讨论】:

      猜你喜欢
      • 2013-12-18
      • 2019-10-07
      • 2021-09-05
      • 2017-10-06
      • 2020-01-29
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多