重新启动背景SVG动画。

20

我有一个元素的背景图像是SVG格式。第一次显示元素时,动画会正确播放。

在后续的显示中(例如,如果通过JavaScript注入元素的副本,或者如果使用CSS / JavaScript删除并重新添加背景图像),动画不会从头开始播放。我认为这是预期功能,因为浏览器认为图像没有被重新加载-它使用内存中已经正在运行的版本。

这里有一个演示(不是我的):http://www.luigifab.info/public/svg-smil/test.html

FirefoxChrome相关的浏览器错误报告,但如上所述,我认为这是预期的功能。

是否有任何方法可以在图像显示时重置/重新播放SVG动画?

我最理想的解决方案是仅使用CSS和SVG-否则,如果这不可能,则使用JavaScript。


你的SVG图像没有正确显示,是吗?这是个问题吗? - Vivek Vikranth
SVG图像已经显示了,只是在后续的显示中没有动画效果。如果您点击上面的演示链接,然后点击“show”,您将看到SVG动画效果。点击“hide”,然后再次点击“show”,SVG将不会动画。 - Alasdair McLeay
你能给我展示你的Animate代码吗? - Vivek Vikranth
它正在使用SVG动画,代码类似于上面演示链接中使用的SVG:http://www.luigifab.info/public/svg-smil/error.svg.php - Alasdair McLeay
7个回答

15

正如 @netsurfer 所说,我通过使用 object 解决了这个问题。以下是一个示例:

<object type="image/svg+xml" data="my.svg"></object>

每次我动态注入SVG object,动画都会从开头开始。


所以你使用<object>作为绝对定位的背景? - Klesun
MVP - 运行得非常好 - Rytis Dereskevicius

13

我认为你的猜测“......因为浏览器不认为图像已经重新加载-它使用内存中的版本,该版本已经在动画了”,是正确的,因为SVG文件已被缓存!所以没有(真正的)'重新加载',动画就不会再次触发。

首先让我们来看看SVG动画。有两个可以在动画元素内使用的属性,用于重复动画-请参见重复动画‘animate’元素。在你的情况下,动画仅运行一次(无重复)。

因此,你需要使用Javascript来“触发”动画。
这在原则上是可能的(例如:高级SVG动画技术),但只有如果SVG文件是DOM的一部分,你可以通过Javascript访问它。因此,你必须将SVG文件包含为<object>

只要你在<img>标记或CSS background-image中使用SVG文件,就无法通过脚本访问该文件。

因此,我能想到的唯一实现你目标的方法是防止浏览器缓存SVG文件(请参见如何(以及如何不)控制缓存),或者将SVG文件用作<object>元素,以便你可以通过Javascript控制动画。

顺便说一句:luigifab的回答并不差。这是一种经常使用的“技巧”,用于强制重新加载文件/图像-请参见缓存技巧


5
一种可能的方法是更改图像URL以强制浏览器重新加载。

每次有人访问页面时都更改它吗?! - Display Name is missing

3

实现luigifab的答案。在url参数结尾加上一些随机字符,这将迫使浏览器认为该资源是一个“新资源”。 演示


2
这对我有用,只需通过添加setTimeout来延迟classList.add('play'),以便可以删除并重新应用"class",将"class"添加和删除到div元素中即可。
CSS
@keyframes play60 {
        0% {
            background-position: 0px 0px;
        }
        100% {
            background-position: -38400px 0px;
        }
    }
    .shapeshifter {
        animation-duration: 1000ms;
        animation-timing-function: steps(60);
        animation-fill-mode: forwards;
        width: 640px;
        height: 640px;
        background-repeat: no-repeat;
    }
    .shapeshifter.play {
        animation-name: play60;
    }

JS:

document.getElementById('shape').addEventListener('mouseover', () => {
    document.getElementById('shape').classList.remove('play')
    setTimeout(() => {
        document.getElementById('shape').classList.add('play');
    }, 1)
})

HTML

<div class="shapeshifter " id="shape" style="background-image: url(shape.svg)"></div>

非常棒的解决方案!我使用了类似的方法,设置了1毫秒的超时,但是我没有添加和删除类,而是将动画名称从“bounce”切换到“none”。 1毫秒后,脚本会重新添加动画名称,动画会再次从头开始播放。 - zombiedoctor

1
使用随机密钥来防止网址缓存。虽然您的示例没有一个长的动画来进行适当的测试,但我已经添加了重复加载图像以使差异明显。

url + "&" + Math.random()

无重新加载演示,使用恒定URLhttp://jsfiddle.net/4ZBLr/8/

重新加载演示,使用随机URL srchttp://jsfiddle.net/4ZBLr/9/


在2020年,&似乎会在Chrome和FF中破坏图像链接。使用#?代替似乎可以解决这个问题。 - V. Rubinetti
可能需要将其转义为"&amp"。 - zombiedoctor

1

我认为在许多情况下,setCurrentTime(0)是最好的解决方案——如果浏览器支持的话。以下是一个示例(当然,假设您使用<object>标记进行嵌入):

let content = document.getElementById("object-id").contentDocument;
let svg = content.getElementsByTagName("svg")[0];
if(svg.getCurrentTime() > 10)
  svg.setCurrentTime(0);

有关相关API的更多信息,请访问此处: https://developer.mozilla.org/zh-CN/docs/Web/API/SVGSVGElement


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接