Javascript 使用 display:none 在 Chrome 上重置 GIF 动画的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10730212/
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-24 02:41:20  来源:igfitidea点击:

Proper way to reset a GIF animation with display:none on Chrome

javascriptjqueryhtmlgoogle-chromeanimated-gif

提问by Fabrício Matté

Title is self-explanatory, but I'll provide a step-by-step view on the matter. Hopefully I'm not the first one to have noticed this (apparently) bug on Webkit/Chrome.

标题是不言自明的,但我将提供有关此事的分步视图。希望我不是第一个在 Webkit/Chrome 上注意到这个(显然)错误的人。

I want to reset a GIF animation. All of the examples I've seen so far either simply set the srcof the image to itself or set it to an empty string followed by the original srcagain.

我想重置一个 GIF 动画。到目前为止,我看到的所有示例要么简单地将src图像的 设置为自身,要么将其设置为空字符串,然后src再次将其设置为原始字符串。

Take a look at this JSFiddlefor reference. The GIF resets perfectly fine on IE, Firefox and Chrome.

看看这个JSFiddle以供参考。GIF 在 IE、Firefox 和 Chrome 上重置得非常好。

The issue which I have is when the image has display:noneon Google Chrome only.

我遇到的问题是图像display:noneGoogle Chrome 上

Check this JSFiddle. The GIF resets fine on IE and Firefox before being displayed in the page, but Chrome simply refuses to reset its animation!

检查这个JSFiddle。在页面中显示之前,GIF 在 IE 和 Firefox 上重置得很好,但 Chrome 只是拒绝重置其动画!

What I've tried so far:

到目前为止我尝试过的:

  • Setting the srcto itself as in Fiddle, doesn't work in Chrome.
  • Setting the srcto an empty string and restoring it to the default, doesn't work either.
  • Putting an wrapper around the image, emptying the container through .html('')and putting the image back inside of it, doesn't work either.
  • Changing the displayof the image through .show()or .fadeIn()right before setting the srcdoesn't work either.
  • src在 Fiddle 中将设置为自身,在 Chrome 中不起作用。
  • 将 设置src为空字符串并将其恢复为默认值也不起作用。
  • 在图像周围放置一个包装器,清空容器.html('')并将图像放回其中,也不起作用。
  • 在设置之前更改或更改display图像也不起作用。.show().fadeIn()src

The onlyworkaround which I've found so far is keeping the image with its default displayand manipulating it through .animate()ing and .css()ing the opacity, height and visibility when necessary to simulate a display:nonebehaviour.

到目前为止,我发现的唯一解决方法是将图像保留为默认值,并在需要模拟行为时display通过.animate()ing 和.css()ing 不透明度、高度和可见性来操纵它display:none

The main reason (context) of this question is that I wanted to reset an ajax loader GIF right before fading it in the page.

这个问题的主要原因(上下文)是我想在页面中淡入淡出之前重置 ajax 加载器 GIF。

So my question is, is there a proper way to reset a GIF image's animation (which avoids Chrome's display:none"bug") or is it actually a bug?

所以我的问题是,是否有一种正确的方法来重置 GIF 图像的动画(避免 Chrome 的display:none“错误”)或者它实际上是一个错误?

(ps. You may change the GIF in the fiddles for a more appropriate/longer animation gif for testing)

(ps。您可以更改小提琴中的 GIF 以获得更合适/更长的动画 gif 以进行测试)

回答by Kal

Chrome deals with style changes differently than other browsers.

Chrome 处理样式更改的方式与其他浏览器不同。

In Chrome, when you call .show()with no argument, the element is not actually shown immediately right where you call it. Instead, Chrome queuesthe application of the new style for execution afterevaluating the current chunk of JavaScript; whereas other browsers would apply the new style change immediately. .attr(), however, does not get queued. So you are effectively trying to set the srcwhen the element is still not visible according to Chrome, and Chrome won't do anything about it when the original srcand new srcare the same.

在 Chrome 中,当你.show()不带参数调用时,元素实际上不会立即显示在你调用它的地方。相反,Chrome 会评估当前 JavaScript 块后将新样式的应用程序排队执行;而其他浏览器会立即应用新的样式更改。,但是,不会排队。因此,根据 Chrome,您正在有效地尝试设置元素何时仍然不可见,而当原始元素和新元素相同时,Chrome 不会对此做任何处理。.attr()srcsrcsrc

Instead, what you need to do is to make sure jQuery sets the srcafterdisplay:blockis applied. You can make use of setTimeoutto achieve this effect:

相反,您需要做的是确保应用了 jQuery 设置src之后display:block。你可以利用setTimeout来达到这个效果:

var src = 'http://i.imgur.com/JfkmXjG.gif';
$(document).ready(function(){
    var $img = $('img');
    $('#target').toggle(
        function(){
            var timeout = 0; // no delay
            $img.show();
            setTimeout(function() {
                $img.attr('src', src);
            }, timeout);
        },
        function(){
            $img.hide();
        }
    );
});

This ensures that srcis set afterdisplay:blockhas been applied to the element.

这确保在应用于元素之后src设置。display:block

The reason this works is because setTimeout queues the function for execution later(however long lateris), so the function is no longer considered to be part of the current "chunk" of JavaScript, and it provides a gap for Chrome to render and apply the display:blockfirst, thus making the element visible before its srcattribute is set.

这个作品的原因是因为setTimeout的队列执行功能(但长期以后的),因此函数不再被认为是JavaScript的当前“块”的一部分,它提供了Chrome的渲染和应用差距第display:block一个,从而在src设置其属性之前使元素可见。

Demo: http://jsfiddle.net/F8Q44/19/

演示:http: //jsfiddle.net/F8Q44/19/

Thanks to shoky in #jquery of freenode IRC for providing a simpler answer.

感谢 freenode IRC 的 #jquery 中的 shoky 提供了一个更简单的答案。



Alternatively, you can force a redraw to flush the batched style changes. This can be done, for example, by accessing the element's offsetHeightproperty:

或者,您可以强制重绘以刷新批量样式更改。例如,这可以通过访问元素的offsetHeight属性来完成:

$('img').show().each(function() {
    this.offsetHeight;
}).prop('src', 'image src');

Demo: http://jsfiddle.net/F8Q44/266/

演示:http: //jsfiddle.net/F8Q44/266/

回答by Niet the Dark Absol

The most reliable way to "reset" a GIF is by appending a random query string. However this does mean that the GIF will be redownloaded every time so make sure it's a small file.

“重置”GIF 的最可靠方法是附加随机查询字符串。但是,这确实意味着每次都会重新下载 GIF,因此请确保它是一个小文件。

// reset a gif:
img.src = img.src.replace(/\?.*$/,"")+"?x="+Math.random();

回答by teebot

This solutionpreloads the gif and takes it out of the dom and then back in the src (thus avoiding another download)

解决方案预加载 gif 并将其从 dom 中取出,然后返回到 src (从而避免再次下载)

I just tested it using jquery to remove the attribute and it works fine.

我刚刚使用 jquery 对其进行了测试以删除该属性,并且它工作正常。

Example:

例子:

<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>

<script>

$(function() {

    $('.reset').click(resetGif);

    function resetGif() 
    {
        $('.img1').removeAttr('src', '');
    }
});

</script>

</head>

<body>
    <img class="img1" src="1.gif" />
    <a href="#" class="reset">reset gif</a>
</body>
</html>

回答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 ayal gelles

here's my hack for background images:

这是我的背景图片技巧:

$(document).on('mouseenter', '.logo', function() {
  window.logo = (window.logocount || 0) + 1;
  var img = new Image();
  var url = "/img/mylogimagename.gif?v=" + window.logocount;
var that = this;
  $(img).load(function(){

     $(that ).css('background-image','url(' + url + ')');
  });
  img.src = url;
});

回答by David Bell

This seemed to work for me in Chrome, it runs each time just before I fade in the image and clears then refills the src and my animation now starts from the beginning every time.

这似乎在 Chrome 中对我有用,它每次在我淡入图像之前运行,然后清除然后重新填充 src,我的动画现在每次都从头开始。

var imgsrc = $('#my_image').attr('src');
$('#my_image').attr('src', '');
$('#my_image').attr('src', imgsrc);

回答by Pratyush

I've a button with the an animated no-loop image in it. I just reload the image with some jquery and this seems to be working for me.

我有一个带有动画无循环图像的按钮。我只是用一些 jquery 重新加载图像,这似乎对我有用。

var asdf = $(".settings-button img").attr("src");
$(".settings-button img").attr("src", "").attr("src", asdf);

回答by Daniel Howard

I experienced problems with all of the above solutions. What finally worked was replacing the src temporarily with a transparent 1px gif:

我遇到了上述所有解决方案的问题。最终起作用的是暂时用透明的 1px gif 替换 src:

var transparent1PxGif = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
var reloadGif = function(img) {
    var src = img.src;
    img.src = transparent1PxGif;
    img.offsetHeight; // triggers browser redraw
    img.src = src;
};

回答by Niet the Dark Absol

It's been several years and I've decided to revisit this since we have a number of new options at our disposal.

几年过去了,我决定重新审视这个问题,因为我们有许多新的选择可供我们使用。

The issue with my previous answeris that it forces a re-download of the GIF every single time you want to re-start it. While that's fine for small files, it's still an overhead that's best avoided if possible.

这个问题我以前的答案是,它迫使GIF的重新下载要每一次重新启动它。虽然这对于小文件来说没问题,但如果可能的话,这仍然是最好避免的开销。

With that in mind, I've got a new solution that uses AJAX to download the GIF once, and then converts it into a data URL (via a FileReader) and uses that as the source with a random query string attached.

考虑到这一点,我有一个新的解决方案,它使用 AJAX 下载 GIF 一次,然后将其转换为数据 URL(通过 FileReader)并将其用作附加随机查询字符串的源。

This way, the browser only ever downloads the image once, and can even cache it properly, and the "reset" pulls from that pre-downloaded resource.

这样,浏览器只下载一次图像,甚至可以正确缓存它,并且“重置”从该预下载的资源中提取。

The only catch, of course, is that you have to make sure it's properly loaded before you can use it.

当然,唯一的问题是您必须确保它已正确加载,然后才能使用它。

Demo: http://adamhaskell.net/misc/numbers/numbers.html

演示:http: //adamhaskell.net/misc/numbers/numbers.html

Relevant code:

相关代码:

var url = "something.gif"; // fallback until the FileReader is done
function setup() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET",url,true);
    xhr.responseType = "blob";
    xhr.onreadystatechange = function() {
        if( this.readyState == 4) {
            var fr = new FileReader();
            fr.onload = function() {
                url = this.result; // overwrite URL with the data one
            };
            fr.readAsDataURL(this.response);
        }
    };
    xhr.send();
}
function getGIF() {
    return url+"?x="+Math.random();
}

回答by Banjo Drill

I came across this thread after searching many others. David Bell's post led me to the solution I needed.

在搜索了许多其他线程后,我遇到了这个线程。David Bell 的帖子让我找到了我需要的解决方案。

I thought I'd post my experience in the event that it could be useful for anyone trying to accomplish what I was after. This is for an HTML5/JavaScript/jQuery web app that will be an iPhone app via PhoneGap. Testing in Chrome.

我想我会发布我的经验,以防它对任何试图完成我所追求的事情的人有用。这是一个 HTML5/JavaScript/jQuery Web 应用程序,它将是一个通过 PhoneGap 的 iPhone 应用程序。在 Chrome 中测试。

The Goal:

目标:

  1. When user taps/clicks button A, an animated gif appears and plays.
  2. When user taps/clicks button B, gif disappears.
  3. When user taps/clicks button A again, after tapping/clicking button B, animated gif should reappear and play from the beginning.
  1. 当用户点击/单击按钮 A 时,会出现并播放动画 gif。
  2. 当用户点击/点击按钮 B 时,gif 消失。
  3. 当用户再次点击/点击按钮 A 时,点击/点击按钮 B 后,动画 gif 应重新出现并从头开始播放。

The Problem:

问题:

  • On tap/click of button A, I was appending the gif to an existing div. It would play fine.
  • Then, on tap/click of button B, I was hiding the container div, then setting the img src of the gif to an empty string (''). Again, no problem (that is, the problem wasn't evident yet.)
  • Then, on tap/click of button A, after tap/click of button B, I was re-adding the path to the gif as the src.

    - This did not work.The gif would show up on subsequent taps/clicks of button A...however, the more I tapped/clicked button A, the more times the gif would load and start over. That is, if I went back and forth, tapping/clicking button A then button B 3 times, the gif would appear and then start/stop/start 3 times...and my whole app started to chug. I guess the gif was being loaded multiple times, even though I had set the src to an empty string when button B was tapped/clicked.

  • 在点击/单击按钮 A 时,我将 gif 附加到现有的 div。它会玩得很好。
  • 然后,在点击/单击按钮 B 时,我隐藏了容器 div,然后将 gif 的 img src 设置为空字符串 ('')。同样,没问题(也就是说,问题还不明显。)
  • 然后,点击/点击按钮 A,点击/点击按钮 B 后,我将 gif 的路径重新添加为 src。

    -这没有用。gif 将显示在按钮 A 的后续点击/点击中……但是,我点击/点击按钮 A 的次数越多,gif 加载和重新开始的次数就越多。也就是说,如果我来回点击/点击按钮 A 和按钮 B 3 次,gif 将出现,然后开始/停止/开始 3 次......我的整个应用程序开始突飞猛进。我想 gif 被多次加载,即使我在点击/单击按钮 B 时将 src 设置为空字符串。

The Solution:

解决方案:

After looking at David Bell's post, I arrived at my answer.

看了大卫贝尔的帖子后,我得出了我的答案。

  1. I defined a global variable (let's call it myVar) that held the container div and the image (with the source path) within.
  2. On the tap/click function of button A, I appended that container div to an existing parent div in the dom.
  3. In that function, I created a new variable that holds the src path of the gif.
  1. 我定义了一个全局变量(我们称之为 myVar),其中包含容器 div 和图像(带有源路径)。
  2. 在按钮 A 的点击/单击功能上,我将该容器 div 附加到 dom 中的现有父 div。
  3. 在该函数中,我创建了一个新变量,用于保存 gif 的 src 路径。

Just like David suggested, I did this (plus an append):

就像大卫建议的那样,我做了这个(加上一个附加):

$('#mainParent').append(myVar);
var imgsrc = $('#my_image').attr('src');
$('#my_image').attr('src', '');
$('#my_image').attr('src', imgsrc);

THEN, in the function for button B, I set the src to an empty string and then removed the div containing the gif:

然后,在按钮 B 的函数中,我将 src 设置为空字符串,然后删除包含 gif 的 div:

$('#my_image').attr('src', '');
$('#mainParent').find('#my_image').remove();

Now, I can tap/click button A then button B then button A, etc., all day long. The gif loads and plays on tap/click of button A, then hides on tap/click of button B, then loads and plays from the beginning on subsequent taps of button A every time with no issues.

现在,我可以整天点击/单击按钮 A,然后是按钮 B,然后是按钮 A,等等。gif 在点击/点击按钮 A 时加载和播放,然后在点击/点击按钮 B 时隐藏,然后在每次随后点击按钮 A 时从头开始加载和播放,没有任何问题。