jQuery 重新启动动画 GIF 作为背景图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7568855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 00:00:26  来源:igfitidea点击:

Restart animated GIF as background-image

jqueryhtmlcssbackground-imageanimated-gif

提问by hpique

Is it possible to restart an animated GIF used as background-image?

是否可以重新启动用作的动画 GIF background-image

Consider this HTML:

考虑这个 HTML:

<div id="face">
    <div id="eyes"></eyes>
</div>

And this style:

还有这种风格:

#eyes.blink {
    background-image:url('blink.gif');
}

I would like the blink.gifanimation to play every time I add the class blinkto #eyes, not just the first time.

我想在blink.gif动画播放每次我的类添加时间blink#eyes,不只是第一次。

I expected this to work:

我希望这能奏效:

function startBlink() {
    $('#eyes').addClass('blink');
}

function stopBlink() {
    $('#eyes').removeClass('blink');
}

The problem is that both Firefox and WebKit browser do not play a background-image GIF animation again once it has played once. Adding/removing the class blink only works the first time.

问题是 Firefox 和 WebKit 浏览器在播放一次背景图像 GIF 动画后都不会再次播放。添加/删除类闪烁仅在第一次有效。

采纳答案by Pat

You can get the animated gif to replay by reloading it. This isn't ideal for bandwidth, especially if your image is large, but it will force a restart of the animation.

您可以通过重新加载动画 gif 来重播它。这对于带宽来说并不理想,尤其是当您的图像很大时,但它会强制重新启动动画。

In my example I'm adding and removing it onclickof <div id="animated">:

在我的例子,我添加和删除它onclick<div id="animated">

$('#animated').click(function() {

    /* Reference to the clicked element and toggle the .go class */
    var $div = $(this);
    $div.toggleClass('go');

    /* Start the animated gif */
    if ($div.hasClass('go')) {

        /* Create an <img> element and give it the animated gif as a src.  To 
           force a reload we add a date parameter to the URL */
        var img = document.createElement('img');
        img.src = "http://yoursite.com/animated.gif?p" + new Date().getTime();

        /* Once the image has loaded, set it as the background-image */
        $(img).load(function(){
            $div.css({backgroundImage: "url("+img.src+")"});
        });

    /* Remove the background-image */        
    } else {
       $div.css({backgroundImage: "none"});
    }
})

Demo of itin action.

演示它在行动。

回答by JVE999

I've found you can also add a ?+Math.random()to the end of the picture src and it'll reload the .gif.

我发现您还可以?+Math.random()在图片 src 的末尾添加一个,它会重新加载 .gif。

回答by Frederic Leitenberger

I combined several parts of the solution to make one whole solution that solves (hopefully) all problems:

我结合了解决方案的几个部分来制作一个解决(希望)所有问题的完整解决方案:

  • Determine the background-image URL of an element (from css background-image)
  • Trigger a restart for that image WITHOUT reloading it from the web
  • Restarting it in all places (without touching each individually)
  • Making sure the target is repainted without artifacts after restarting the animation
  • 确定元素的背景图片 URL(来自 css background-image
  • 触发该图像的重新启动,而无需从 Web 重新加载它
  • 在所有地方重新启动它(不单独触摸每个地方)
  • 确保在重新启动动画后重新绘制目标而没有工件

In my solution i create helper images that are added to the body but hidden in a way so they are still rendered by the browser but won't interact with the page visually using position: absolute; left: -5000px;.

在我的解决方案中,我创建了添加到正文但以某种方式隐藏的辅助图像,因此它们仍然由浏览器呈现,但不会使用position: absolute; left: -5000px;.

A reference to our helper images is cached in resetHelperImagesso we can reuse them for the same image in subsequent calls.

对辅助图像的引用被缓存在其中,resetHelperImages因此我们可以在后续调用中将它们重用于同一图像。

I am using jQuery for my example, but it could be adapted to work without jQuery, too.

我在我的例子中使用了 jQuery,但它也可以在没有 jQuery 的情况下工作。

Tested in: Chrome (Version 43.0.2357.130 m)

测试:Chrome(版本 43.0.2357.130 m)

var resetHelperImages = {};

function restartAnimation(elem) {
  elem = $(elem);
  for (var i = 0; i < elem.length; i++) {
    var element = elem[i];
    // code part from: http://stackoverflow.com/a/14013171/1520422
    var style = element.currentStyle || window.getComputedStyle(element, false);
    // var bgImg = style.backgroundImage.slice(4, -1).replace(/"/g, '');
    var bgImg = style.backgroundImage.match(/url\(([^\)]+)\)/)[1].replace(/"/g, '');
    // edit: Suggestion from user71738 to handle background-images with additional settings

    var helper = resetHelperImages[bgImg]; // we cache our image instances
    if (!helper) {
      helper = $('<img>')
        .attr('src', bgImg)
        .css({
          position: 'absolute',
          left: '-5000px'
        }) // make it invisible, but still force the browser to render / load it
        .appendTo('body')[0];
      resetHelperImages[bgImg] = helper;
      setTimeout(function() {
        helper.src = bgImg;
      }, 10);
      // the first call does not seem to work immediately (like the rest, when called later)
      // i tried different delays: 0 & 1 don't work. With 10 or 100 it was ok.
      // But maybe it depends on the image download time.
    } else {
      // code part from: http://stackoverflow.com/a/21012986/1520422
      helper.src = bgImg;
    }
  }
  // force repaint - otherwise it has weird artefacts (in chrome at least)
  // code part from: http://stackoverflow.com/a/29946331/1520422
  elem.css("opacity", .99);
  setTimeout(function() {
    elem.css("opacity", 1);
  }, 20);
}
.myBgImageClass {
  background-image: url('http://i410.photobucket.com/albums/pp184/OllieMarchant/Countup.gif');
  width: 100px;
  height: 150px;
  background-size: 100%;
  background-repeat: no-repeat;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="myBgImageClass"></div>
<button onclick="restartAnimation($('.myBgImageClass'))">restart</button>

回答by Jeff Ward

There is an alternative that does not reload the GIF every time and waste bandwidth.

有一种替代方法,它不会每次都重新加载 GIF 并浪费带宽。

It involves storing the GIF as Base64 in memory (circumventing browser cache), and uses the FileReader API (which seems to be supported in all modern browsers). Note that loading images this way is subject to cross-origin policy (unlike the image reload solutions.)

它涉及将 GIF 作为 Base64 存储在内存中(绕过浏览器缓存),并使用 FileReader API(似乎所有现代浏览器都支持)。请注意,以这种方式加载图像受跨域策略的约束(与图像重新加载解决方案不同。)

Update:Browser caching is getting smarter about caching background image data URI's, causing the animation not to start over. I found I had to add a cache-busting random string to the data url now (which according to the DataURI Scheme, should be considered an optional attribute. Tested in Chrome & IE Edge.)

更新:浏览器缓存在缓存背景图像数据 URI 方面变得越来越智能,导致动画无法重新开始。我发现我现在必须向数据 url 添加一个缓存破坏随机字符串(根据DataURI Scheme,这应该被视为一个可选属性。在 Chrome 和 IE Edge 中测试。)

See it in action: http://jsfiddle.net/jcward/nknLrtzL/10/

看到它在行动:http: //jsfiddle.net/jcward/nknLrtzL/10/

Here's how it works. This function loads the image as a Base64-encoded string.

这是它的工作原理。此函数将图像加载为 Base64 编码的字符串。

function toDataUrl(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var reader = new FileReader();
    reader.onloadend = function() {
      callback(reader.result);
    }
    reader.readAsDataURL(xhr.response);
  };
  xhr.open('GET', url);
  xhr.responseType = 'blob'; // IE11, set responseType must come after .open()
  xhr.send();
}

Then, any time you want to restart the GIF animation, change the background-imageproperty to none, then the base64 string (in some browsers, you need to re-add the child to trigger the update without a setTimeout):

然后,任何时候要重新启动GIF动画,将background-image属性更改为none,然后是base64字符串(在某些浏览器中,您需要重新添加子项以触发更新而无需setTimeout):

$div.css({backgroundImage: "none"});
$div.parent().add($div); // Some browsers need this to restart the anim
// Slip in a cache busting random number to the data URI attributes
$div.css({backgroundImage: "url("+img_base64.replace("image/gif","image/gif;rnd="+Math.random())+")"});

Thanks to this answerfor the toDataURLfunction (with fix for IE11.)

感谢这个答案toDataURL功能(有固定的IE11。)

回答by nico

Just because I still need this every now and then I figured the pure JS function I use might be helpful for someone else. This is a pure JS way of restarting an animated gif, without reloading it. You can call this from a link and/or document load event.

只是因为我仍然时不时地需要它,我认为我使用的纯 JS 函数可能对其他人有帮助。这是一种无需重新加载即可重新启动动画 gif 的纯 JS 方式。您可以从链接和/或文档加载事件中调用它。

<img id="img3" src="../_Images/animated.gif">

<a onClick="resetGif('img3')">reset gif3</a>

<script type="text/javascript">

// reset an animated gif to start at first image without reloading it from server.
// Note: if you have the same image on the page more than ones, they all reset.
function resetGif(id) {
    var img = document.getElementById(id);
    var imageUrl = img.src;
    img.src = "";
    img.src = imageUrl;
};

</script>

On some browsers you only need to reset the img.src to itself and it works fine. On IE you need to clear it before resetting it. This resetGif() picks the image name from the image id. This is handy in case you ever change the actual image link for a given id because you do not have to remember to change the resetGiF() calls.

在某些浏览器上,您只需要将 img.src 重置为自身,它就可以正常工作。在 IE 上,您需要在重置之前清除它。此 resetGif() 从图像 ID 中选择图像名称。这在您更改给定 id 的实际图像链接时非常方便,因为您不必记住更改 resetGiF() 调用。

--Nico

--妮可

回答by Richard

Have you considered using the same image twice called blink.gif and blink2.gif, adding two classes for them and toggling between classes?

您是否考虑过两次使用相同的图像,称为blink.gif 和blink2.gif,为它们添加两个类并在类之间切换?

<div id="face">
    <div id="eyes"></eyes>
</div>

.blink {
    background-image:url('blink.gif');
}

.blink2 {
    background-image:url('blink2.gif');
}

function MakeBlink()
{
   if ($('#eyes').hasClass('blink'))
   {
      $('#eyes').removeClass('blink').addClass('blink2');
   } else
   {
     $('#eyes').removeClass('blink2').addClass('blink');
   }
}

回答by Benjamin Knight

For some reason this works:

出于某种原因,这有效:

// Append the image to the page
var i = new Image();
i.src = 'some.gif';
document.body.appendChild(i);

// Now execute this line and the gif will restart
// (anywhere it appears on the page, including CSS backgrounds)
i.src = 'some.gif';

This requires an actual image DOM element to be appended to the page, but you can hide it with visibility: hidden. This doesn'trequire the image to be downloaded over the network multiple times.

这需要将实际的图像 DOM 元素附加到页面,但您可以使用visibility: hidden. 这不需要多次通过网络下载图像。

I only tested this in Firefox and Chrome. Not sure about other browsers.

我只在 Firefox 和 Chrome 中测试过。不确定其他浏览器。

回答by user71738

Regarding this answerposted by Frederic Leitenberger, I found it to work wonderfully.

关于Frederic Leitenberger发布的这个答案,我发现它非常有效。

However, it breaks down if your background-image has multiple, layered parts, like this:

但是,如果您的背景图像具有多个分层部分,则它会崩溃,如下所示:

background-image: url(https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg),
    radial-gradient(ellipse at center,
        rgba(255,255,255,1) 0%,
        rgba(255,255,255,1) 50%,
        rgba(255,255,255,0) 80%);

To get around this limitation, I modified the line that finds the background image url, like so:

为了解决这个限制,我修改了查找背景图片 url 的行,如下所示:

var bgImg = style.backgroundImage.match(/url\(([^\)]+)\)/)[1].replace(/"/g, '');

This uses a regular expression to extract just the URL portion of the background-image.

这使用正则表达式来提取背景图像的 URL 部分。

I would have added this as a comment to the linked answer, but I'm a noob without reputation, so was blocked from doing so. Those with adequate rep may want to add the line to the actual answer.

我会将此添加为链接答案的评论,但我是一个没有声誉的菜鸟,因此被阻止这样做。那些有足够代表的人可能希望将这行添加到实际答案中。