23

タイトルは一目瞭然ですが、段階的に説明します。うまくいけば、私はWebkit / Chromeのこの(明らかに)バグに気付いた最初の人ではありません。

GIFアニメーションをリセットしたい。これまでに見たすべての例でsrcは、画像のをそれ自体に設定するか、空の文字列に設定してから元の画像をsrc再度設定します。

参考までに、このJSFiddleをご覧ください。GIFは、IE、Firefox、Chromeで完全に正常にリセットされます。

私が抱えている問題は、画像がGoogleChromeのみdisplay:noneにある場合です。

このJSFiddleを確認してください。GIFは、ページに表示される前にIEとFirefoxで正常にリセットされますが、Chromeは単にアニメーションのリセットを拒否します。

私がこれまでに試したこと:

  • Fiddleのようにそれ自体に設定するsrcと、Chromeでは機能しません。
  • を空の文字列に設定srcしてデフォルトに戻すこともできません。
  • 画像の周りにラッパーを配置し、コンテナを空にして.html('')画像をその中に戻すことも機能しません。
  • を設定する直前または設定する直前にdisplay画像を変更しても機能しません。.show().fadeIn()src

私がこれまでに見つけた唯一の回避策は、画像をデフォルトのままにし、動作をシミュレートするために必要に応じて不透明度、高さ、および可視性displayを操作すること.animate()です。.css()display:none

この質問の主な理由(コンテキスト)は、ページでフェードする直前にajaxローダーGIFをリセットしたかったためです。

だから私の質問は、GIF画像のアニメーションをリセットする適切な方法はありますか(Chromeのdisplay:none「バグ」を回避します)、それとも実際にはバグですか?

(ps。テスト用のより適切で長いアニメーションGIFに、フィドルのGIFを変更できます)

4

12 に答える 12

33

GIFを「リセット」する最も信頼できる方法は、ランダムなクエリ文字列を追加することです。ただし、これはGIFが毎回再ダウンロードされることを意味するため、小さいファイルであることを確認してください。

// reset a gif:
img.src = img.src.replace(/\?.*$/,"")+"?x="+Math.random();
于 2012-05-24T02:08:26.727 に答える
31

Chromeは、他のブラウザとは異なる方法でスタイルの変更を処理します。

Chromeでは、.show()引数なしで呼び出すと、要素は実際には呼び出した場所にすぐには表示されません。代わりに、Chromeは、JavaScriptの現在のチャンクを評価した、実行のために新しいスタイルのアプリケーションをキューに入れます。一方、他のブラウザは新しいスタイルの変更をすぐに適用します。ただし、キューには入れられません。そのため、Chromeに従って要素がまだ表示されない場合を効果的に設定しようとしています。また、元の要素と新しい要素が同じである場合、Chromeはその要素について何もしません。.attr()srcsrcsrc

代わりに、jQueryがsrc after 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();
        }
    );
});

これにより、要素に適用されたsrcにが設定されることが保証されます。 display:block

これが機能する理由は、setTimeoutが関数を後で実行するためにキュー入れるためです(ただし、後で実行されます)。そのため、関数はJavaScriptの現在の「チャンク」の一部とは見なされなくなり、Chromeがレンダリングして適用するためのギャップが提供されます。 1つ目は、属性が設定さdisplay:blockれる前に要素が表示されるようにするためです。src

デモ: http: //jsfiddle.net/F8Q44/19/

より簡単な答えを提供してくれたfreenodeIRCの#jqueryのshokyに感謝します。


または、再描画を強制して、バッチ処理されたスタイルの変更をフラッシュすることもできます。これは、たとえば、要素のoffsetHeightプロパティにアクセスすることで実行できます。

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

デモ: http: //jsfiddle.net/F8Q44/266/

于 2014-01-14T02:13:07.167 に答える
5

私が今でもこれを必要としているという理由だけで、私が使用している純粋な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>

一部のブラウザでは、img.srcをそれ自体にリセットするだけで、正常に機能します。IEでは、リセットする前にクリアする必要があります。このresetGif()は、画像IDから画像名を選択します。これは、resetGiF()呼び出しを変更することを覚えておく必要がないため、特定のIDの実際の画像リンクを変更する場合に便利です。

-ニコ

于 2015-02-24T15:21:20.873 に答える
4

このソリューションは、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>
于 2012-11-19T12:27:06.987 に答える
2

これはChromeで機能しているように見えました。画像をフェードインする直前に毎回実行され、srcをクリアしてから再入力すると、アニメーションが毎回最初から開始されます。

var imgsrc = $('#my_image').attr('src');
$('#my_image').attr('src', '');
$('#my_image').attr('src', imgsrc);
于 2014-04-14T15:02:50.830 に答える
1

背景画像のハックは次のとおりです。

$(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;
});
于 2014-01-25T15:26:36.843 に答える
1

アニメーション化されたループなしの画像が入ったボタンがあります。jqueryを使用して画像をリロードするだけで、これは機能しているようです。

var asdf = $(".settings-button img").attr("src");
$(".settings-button img").attr("src", "").attr("src", asdf);
于 2016-08-30T17:23:36.913 に答える
1

上記のすべての解決策で問題が発生しました。最終的に機能したのは、一時的にsrcを透明な1pxgifに置き換えることでした。

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;
};
于 2017-06-13T08:42:46.693 に答える
0

他の多くのスレッドを検索した後、このスレッドに出くわしました。David Bellの投稿により、私は必要な解決策にたどり着きました。

自分の経験を投稿して、自分が求めていたものを成し遂げようとしている人に役立つと思いました。これは、PhoneGapを介してiPhoneアプリになるHTML5 / JavaScript /jQueryWebアプリ用です。Chromeでのテスト。

目標:

  1. ユーザーがボタンAをタップ/クリックすると、アニメーションGIFが表示されて再生されます。
  2. ユーザーがボタンBをタップ/クリックすると、gifが消えます。
  3. ユーザーがボタンAをもう一度タップ/クリックすると、ボタンBをタップ/クリックした後、アニメーションGIFが再表示され、最初から再生されます。

問題:

  • ボタンAをタップ/クリックすると、既存のdivにgifが追加されていました。それはうまくいくでしょう。
  • 次に、ボタンBをタップ/クリックして、コンテナーdivを非表示にし、gifのimg srcを空の文字列('')に設定しました。繰り返しますが、問題はありません(つまり、問題はまだ明らかではありませんでした)。
  • 次に、ボタンAをタップ/クリックし、ボタンBをタップ/クリックした後、gifへのパスをsrcとして再度追加していました。

    -これは機能しませんでした。gifはボタンAの後続のタップ/クリックで表示されます...ただし、ボタンAをタップ/クリックすればするほど、gifが読み込まれて最初からやり直す回数が増えます。つまり、ボタンA、ボタンBの順に3回タップ/クリックすると、gifが表示され、開始/停止/開始が3回繰り返され、アプリ全体が動き始めました。ボタンBをタップ/クリックしたときにsrcを空の文字列に設定したにもかかわらず、gifが複数回読み込まれていたと思います。

ソリューション:

デビッド・ベルの投稿を見た後、私は自分の答えにたどり着きました。

  1. コンテナdivと画像(ソースパスを含む)を保持するグローバル変数(myVarと呼びます)を定義しました。
  2. ボタンAのタップ/クリック機能で、そのコンテナdivをdom内の既存の親divに追加しました。
  3. その関数で、gifのsrcパスを保持する新しい変数を作成しました。

デビッドが提案したように、私はこれを行いました(さらに追加):

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

次に、ボタンBの関数で、srcを空の文字列に設定してから、gifを含むdivを削除しました。

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

これで、ボタンA、ボタンB、ボタンAなどを1日中タップ/クリックできます。gifは、ボタンAのタップ/クリックでロードおよび再生され、ボタンBのタップ/クリックで非表示になり、ボタンAの後続のタップで最初から問題なくロードおよび再生されます。

于 2014-10-30T03:16:58.910 に答える
0

私はこの問題の完全な解決策を考え出しました。それはここで見つけることができます:https ://stackoverflow.com/a/31093916/1520422

私のソリューションは、ネットワークから画像データを再ロードせずにアニメーションを再開します。

また、(クロムで)発生したいくつかのペイントアーティファクトを修正するために、イメージを再ペイントするように強制します。

于 2015-06-27T22:02:28.053 に答える
0

数年が経ちましたが、新しいオプションがたくさんあるので、これを再検討することにしました。

私の以前の回答の問題は、GIFを再起動するたびにGIFの再ダウンロードを強制することです。これは小さなファイルには問題ありませんが、それでもオーバーヘッドであり、可能であれば回避するのが最善です。

そのことを念頭に置いて、AJAXを使用してGIFを一度ダウンロードし、それを(FileReaderを介して)データURLに変換し、ランダムなクエリ文字列が添付されたソースとして使用する新しいソリューションがあります。

このように、ブラウザは画像を1回だけダウンロードし、適切にキャッシュすることもできます。「リセット」は、事前にダウンロードされたリソースから取得します。

もちろん、唯一の落とし穴は、使用する前に正しくロードされていることを確認する必要があるということです。

デモ:http ://adamhaskell.net/misc/numbers/numbers.html

関連コード:

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();
}
于 2017-07-05T15:15:15.977 に答える
0

gifアニメーションをリセット

ブラウザがレンダリングすると、属性でimg指定されたソースsrcが将来の再利用のためにメモリにキャッシュされます。これにより、ページの読み込み/再読み込みの速度を上げるだけでなく、ネットワークの負荷を減らすことができます。そして、この動作はほとんどすべての人に適しています。実際には、これが最も最適で要求の厳しいオプションだからです。

ただし、いつものように、例外があります。私はいくつかの問題を解決するdataUrlベースのアニメーション更新オプションを思いついた。

解決された問題:

  1. ループのないアニメーション(ループ= 1 )でgif画像を表示する必要があります。これは同じである可能性があります。ただし、そのような画像が1つ表示された場合は、同じ画像の他の画像のアニメーションを変更せずにアニメーションを再生する必要があります。同じ画像をサーバーから1回だけロードする必要があります。スタックオーバーフローsrcsrc

  2. gifアニメーションをリセットします。

  3. ホバーでアニメーションを開始します

src属性をリセット

画像の属性をクリアするソリューションを使用するsrcと、同じソースを持つすべての画像がアニメーションを再生します。残念ながら、なぜこれが起こっているのかまだ完全には理解していませんでしたが、それは正しい作業を妨げます。

短所

  • 同じsrcを持つすべての画像のアニメーションをリセットします。
  • モバイルデバイスに問題があります

長所

  • 簡単で速い

ランダムクエリでURLを変更する

このソリューションは、属性の最後にランダムなクエリパラメータを追加することで構成されsrcます。これにより、すべての画像のソースが異なり、互いに独立してアニメーション化されます。1つの大きな脂肪NOがあります:これは、画像をダウンロードするようにサーバーに絶えず要求することになり、したがって、それらはもはやキャッシュされません。また、100枚の同一の画像を表示する必要がある場合、サーバーへのリクエストは100回になります。ラフでタフですが、常に機能します。

短所

  • 一意のクエリを持つ各画像がサーバーから再読み込みされます。

長所

  • 簡単で速い

dataUrlの変更(提案されたソリューション)

データURL(data:スキームの前に付けられたURL)を使用すると、コンテンツ作成者は小さなファイルをドキュメントにインラインで埋め込むことができます。それらは、その名前がWHATWGによって廃止されるまで、以前は「データURI」と呼ばれていました。 MDN

このドキュメントのdataUrl構造:

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

そして、これは仕様でどのように示されているかです:

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

の説明をよく見ると、そこにmediatype奇妙な parameterことが示されています。しかし、仕様もあります:

     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

ご覧のとおり、任意のパラメーターを指定できます。主なことは、上記の要件を満たしていることです。したがって、メディアタイプに追加の属性を埋め込むことができます。これは画像にまったく影響を与えませんが、データのURLは同じ画像とは異なります。

一般化されたアルゴリズム:

  1. 通常のリクエストで画像を読み込み、作成されたdataUrlからメタデータを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"src=data:image/gif;base64;${Math.random()}${dataUrl}"

  2. 以上です!

バニラ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>

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;
于 2021-08-26T07:30:25.423 に答える