English 中文(简体)
将 GIF 动画重新设置为显示: 铬上的无
原标题:Proper way to reset a GIF animation with display:none on Chrome

标题不言自明,但我将对此问题提供一步一步的观点。 希望我不是第一个在Webkit/Chrome上注意到这个(显然)错误的人。

我想重置一个 GIF 动画。 到目前为止我所看到的所有示例要么只是将图像的 rc 设置为自己,要么将其设置为空字符串,然后是原始的 rc

查看这个“ 强势” href=“ http://jsfiddle. net/ult_ combo/ Fuy9w/3/” rel=“ noreferrer” > JSFiddle < /a/ strong> 参考。 GIF在 IE、 Firefox 和 Chrome 上完全精细的重提。

我的问题是,当图像有 display:noone on < strong> Google Chrome only 上的 display:none 图像时。

选中此项< 坚固> a href=" http://jsfiddle. net/ult_ combo/ F8Q44/3/" rel= "noreferrer" > JSFiddle 。 GIF在页面显示 IE 和 Firefox 之前的罚款, 但是 Chrome 拒绝重置其动画!

至今为止我尝试过的 < 坚固> :

  • Setting the src to itself as in Fiddle, doesn t work in Chrome.
  • Setting the src to 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 display of the image through .show() or .fadeIn() right before setting the src doesn t work either.

我迄今找到的 < 坚固 > 唯一的 < / 坚固 > 工作环境正在将图像保留为默认的 < code> display , 并通过 < code>. animate () 和 . css () 进行操纵, 以模拟 < code> display: noone 行为所需的不透明性、 高度和可见性 。

这个问题的主要原因(引文)是我想重置一个ajax装载器 GIF,

所以,我的问题是,是否有合适的方法重设 GIF 图像的动画( 避免 Chrome s display: noone "bug" ), 或者它实际上是一个错误?

(ps. 您可以更改小提琴类中的 GIF, 以获得更适合/ 更长的动画 gif 用于测试) 。

最佳回答

铬处理样式变化的方式不同于其他浏览器。

在铬中,当您调用 .show () () 时,该元素不会在您调用该元素的地方立即立即显示。 相反, Chrome queues 应用新样式执行 后 < em> /em> 来评估 JavaScript 的当前块块; 而其他浏览器会立即应用新样式的更改 。 .attr () 也不会被排队。 因此,您正在有效地尝试设置 s>rc , 当根据 Chrome,该元素仍然不可见时, 当原始的 src 和新的 都相同时, Chrome 将不做任何事情。

相反,您需要做的是确保jQuery设置 src display:\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

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();
        }
    );
});

这确保了 >src 被设置为 after display: block 已被适用于元素 。

之所以如此工作, 是因为 SetTimeout 队列是执行 < em>later 的函数( 不论时间长 < em>later ), 所以该函数不再被视为 JavaScript 中当前“ chunk” 的一部分, 并且它为Chrome提供一个空白, 使其无法生成并应用 < code> display: first block , 从而使得元素在设定 < code> rc 属性之前能够显示 。

说明:http://jsfiddle.net/F8Q44/19/" rel="noreferrer" >http://jsfiddle.net/F8Q44/19/

多亏了自由节点的IRC在#jquery上充斥着一个简单解答。


或者,您可以强制重新绘制以冲刷分批样式的更改。例如,可以通过访问元素 s < code> offsectionH8 属性来做到这一点:

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

说明:"http://jsfiddle.net/F8Q44/266/" rel="nreferrer" >http://jsfiddle.net/F8Q44/266/

问题回答

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

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

这似乎对我在铬州有效, 每次它运行之前,我都会在图像中消失, 清除,然后再填充螺旋, 我的动画现在从每次开始开始。

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

仅仅因为我现在仍然需要这个,然后我发现我使用的纯JS功能也许对别人有用。 这是在不重新加载的情况下重新启动动画吉夫的纯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>

在一些浏览器上,您只需要将 img.src 重置为本身即可正常工作。在 IE 上,您需要在重置前清理它。 此重置 Gif () 从图像 id 中选择图像名称。 如果您更改给定 id 的实际图像链接, 因为您不需要记得更改 resetGiF () 调用 。

-- -- 尼科

这 < a href=" "https://stackoverflow.com/ questions/3191922/restart-an-an-animated-gif-from-javascript-unt-reload-reloading-the-image" > 解决方案 预加载 gif 并把它从 Dom 中取出来, 然后返回 src (这样避免再次下载)

我刚刚用Jquery来测试它 去除属性 效果很好

示例:

<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>

Reset gif animation

当浏览器创建 img 时, rc 属性中指定的源会被缓存到内存中, 以便将来重新使用。 这样可以提高页面加载/ 重新加载的速度, 并减少网络的负载。 而这种行为对每个人都适用, 因为在现实中, 这是最理想和最需要的选择 。

然而,和往常一样,也有例外。我提出了一个基于数据Url的动画更新选项,解决了几个问题。

Issues solved:

  1. 需要显示具有动画且没有循环的动画(loop=1 )的 < enger> / strong > 图像,这些图像可能具有相同的 < code> src 。 但是,当出现一张这样的图片时,它必须播放动画,而不以相同的 src 更改其他图片的动画。同一图片只能从服务器上装入一次 。 < a href="https://stackoverflow.com/ questions/68917982/how-can-yo-instantate-a-gif-files- a-react- app/68918284 > > 。

  2. 重置 gif 动画 。

  3. 在悬盘上开始动画

Reset src attribute

如果我们使用一个能清除图像 < code> src 属性的解决方案, 那么所有使用同一来源的图像都会重播动画。 不幸的是, 我仍然不完全理解为什么会发生这种情况, 但是它会干扰正确的工作 。

Cons

Pros

  • Easy and fast

Modify url with random query

此解决方案包括在 < code> src 属性结尾处添加随机查询参数, 这样所有图像都会有不同的源, 因此它们会相互独立地动画 。 有一个大胖子 < nuger > no : 这将导致不断请求服务器下载图片, 因此它们将不再缓存 。 如果我们需要显示 100 张相同的图片, 那么服务器将会收到 100 个请求 。 粗糙和坚硬, 但总是有效 。

Cons

  • Each picture with a unique query will be reloaded from the server.

Pros

  • Easy and fast

Modify dataUrl (Proposed Solution)

Data URLs, URLs prefixed with the data: scheme, allow content creators to embed small files inline in documents. They were formerly known as "data URIs" until that name was retired by the WHATWG. MDN

此文档中的数据Url结构 :

data:[<mediatype>][;base64],<data>

这就是"https://datatracker.ietf.org/doc/html/rfc2397" rel="不跟随 noreferrer">的特写 所显示的:

dataurl    := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype  := [ type "/" subtype ] *( ";" parameter )
data       := *urlchar
parameter  := attribute "=" value

如果您仔细查看 mediatype 的描述, 就会看到一些奇怪的 参数 。 但是, 还有一个 < a href=>。 https:// datatracker. ietf.org/doc/html/rfc2045#section-5. 1, rel= "nofollown norefererr" > 的特性 < /a> :

     attribute := token
                  ; Matching of attributes
                  ; is ALWAYS case-insensitive.

     value := token / quoted-string

     token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials>

     tspecials :=  "(" / ")" / "<" / ">" / "@" /
                   "," / ";" / ":" / "" / <">
                   "/" / "[" / "]" / "?" / "="
                   ; Must be in quoted-string,
                   ; to use within parameter values

As can be seen, we can specify any parameter, the main thing is that it meets the requirements presented above! Therefore, we can embed an additional attribute in the mediatype, which will not affect the image in any way, but the data url will differ from the same image.

Generalized algorithm:

  1. We load the image through a regular request and remove the metadata from created dataUrl from blob.
fetch("https://cdn140.picsart.com/330970106009201.gif").then(async (res) => {
  const blob = await res.blob();
  const reader = new FileReader();
  reader.onload = (ev) => {
    // It would be reasonable to remove metadata to the point!
    // But for simplicity, I m using this implementation.
    const dataUrl = ev.currentTarget.result.replace(
      "data:image/gif;base64",
      ""
    );
  };
  reader.readAsDataURL(blob);
});
  1. 创建/编辑 img 元素, 包含 src 属性 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

  2. 就这样!

Example Vanila JS

const url = "https://cdn140.picsart.com/330970106009201.gif";

function loadImage(src) {
  fetch(src)
    .then((res) => res.blob())
    .then(async(blob) => {
      const reader = new FileReader();
      reader.onload = (ev) => {
        const dataUrl = ev.currentTarget.result.replace("data:image/gif;base64", "")
        const container = document.getElementById("container");
        while (container.firstChild) {
          container.firstChild.remove()
        }
        for (let i = 0; i < 6; i++) {
          const img = document.createElement("img");
          img.setAttribute("src", `data:image/gif;base64;gif-id=${Date.now()}${dataUrl}`)
          container.appendChild(img);
          img.addEventListener( click , ev => {
            img.setAttribute("src", `data:image/gif;base64;gif-id=${Date.now()}${dataUrl}`)
          })
        }
      };
      reader.readAsDataURL(blob);
    });
}

loadImage(url);

function updateImage() {
  const newSrc = document.getElementById("image-src");
  loadImage(document.getElementById("image-src").value);
}
#main {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

img {
  width: 128px;
  height: 128px;
  padding: 5px;
}
<div id="main">
  <label>Change gif url if current will become unavailable </label>
  <input id="image-src" value="https://cdn140.picsart.com/330970106009201.gif"></input>
  <button onclick="updateImage()">Update image source attribute</button>
  <span>Click to reset!</span>
  <div id="container">
  </div>
</div>

Example React

import React, { useState, useRef } from "react";

function App() {
  const [stars, setStars] = useState(0);
  const [data, setData] = useState(null);

  const ref = useRef(null);

  React.useEffect(() => {
    fetch("https://cdn140.picsart.com/330970106009201.gif")
      .then((res) => res.blob())
      .then(async (text) => {
        const reader = new FileReader();
        reader.onload = (ev) => {
          setData(ev.currentTarget.result.replace("data:image/gif;base64", ""));
        };
        reader.readAsDataURL(text);
      });
  }, []);

  return (
    <React.Fragment>
      <p onClick={() => setStars((s) => s + 1)}>+</p>
      {data &&
        new Array(stars).fill().map((s, ind) => {
          return <Star src={data} key={ind}></Star>;
        })}
      <p onClick={() => setStars((s) => (s === 0 ? 0 : s - 1))}>-</p>
    </React.Fragment>
  );
}

export function Star(props) {
  const [id] = useState(Math.random());

  return (
    <img
      className="icon"
      src={`data:image/gif;base64;gif-id=${id}` + props.src}
      alt="animated star"
    />
  );
}

export default App;

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

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

我在这里黑客用于背景图像 :

$(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;
});

最终有效的是暂时用透明 1px gif 来取代螺旋:

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;
};

几年来,我决定重新讨论这个问题,因为我们有若干新的选择可供我们选择。

>>我先前的回答 的问题是,每次你想重新启动GIF,它都会迫使它重新下载GIF。虽然对小文件罚款,但它仍然是最好避免的间接费用。

考虑到这一点,我找到了一个新的解决方案, 使用 AJAX 下载一次GIF, 然后将其转换成数据 URL( 通过文件检索器), 并使用该源作为随机查询字符串的源 。

这样,浏览器只下载过一次图像, 甚至可以正确缓存它, 而“ 重设” 从预卸载的资源中拉动 。

当然,唯一的收获是,在你使用之前,你必须先确保它适当地装上子弹。

说明: