wake-up-neo.com

Die richtige Methode zum Zurücksetzen einer GIF-Animation mit Anzeige: keine in Chrome

Der Titel ist selbsterklärend, aber ich werde Schritt für Schritt die Angelegenheit erläutern. Hoffentlich bin ich nicht der erste, der diesen (scheinbar) Fehler auf Webkit/Chrome bemerkt hat.

Ich möchte eine GIF-Animation zurücksetzen. Alle Beispiele, die ich bisher gesehen habe, setzen entweder einfach src des Bildes auf sich selbst oder setzen eine leere Zeichenfolge, gefolgt von dem ursprünglichen src.

Sehen Sie sich dieses JSFiddle als Referenz an. Das GIF wird auf IE, Firefox und Chrome perfekt zurückgesetzt.

Das Problem, das ich habe, ist, wenn das Bild display:none auf nur Google Chrome hat.

Überprüfen Sie dieses JSFiddle. Die GIF-Einstellungen werden in IE und Firefox zurückgesetzt, bevor sie auf der Seite angezeigt werden. Chrome weigert sich jedoch einfach, die Animation zurückzusetzen!

Was ich bisher ausprobiert habe:

  • Das Einstellen von src auf sich selbst wie in Fiddle funktioniert in Chrome nicht.
  • Wenn Sie src auf eine leere Zeichenfolge setzen und den Standardwert wiederherstellen, funktioniert dies ebenfalls nicht.
  • Das Einfügen eines Wrappers um das Bild, das Leeren des Containers durch .html('') und das Einfügen des Bildes in das Bild funktioniert nicht.
  • Das Ändern der display des Bildes durch .show() oder .fadeIn() direkt vor dem Einstellen von src funktioniert ebenfalls nicht.

Die einzige Problemumgehung, die ich bisher gefunden habe, besteht darin, das Bild mit dem Standardwert display zu belassen und es durch .animate()ing und .css()ing zu bearbeiten, falls dies erforderlich ist, um ein display:none-Verhalten zu simulieren.

Der Hauptgrund (Kontext) dieser Frage ist, dass ich einen Ajax Loader GIF direkt vor dem Einblenden in die Seite zurücksetzen wollte.

Meine Frage ist also: Gibt es einen geeigneten Weg, um die Animation eines GIF-Bildes zurückzusetzen (was Chrome display:none "Bug" vermeidet) oder ist es tatsächlich ein Fehler?

(ps. Sie können die GIF in den Geigen ändern, um ein besseres/längeres Animationsgif zum Testen zu erhalten.)

16

Chrome behandelt Stiländerungen anders als andere Browser.

Wenn Sie in Chrome .show() ohne Argument aufrufen, wird das Element nicht direkt dort angezeigt, wo Sie es aufrufen. Stattdessen verwendet Chrome Queues die Anwendung des neuen Stils für die Ausführung after, um den aktuellen JavaScript-Block zu bewerten. Andere Browser würden die neue Stiländerung sofort anwenden. .attr() wird jedoch nicht in die Warteschlange gestellt. Sie versuchen also effektiv, die Variable src zu setzen, wenn das Element nach Chrome immer noch nicht sichtbar ist. Chrome unternimmt nichts dagegen, wenn die ursprüngliche Variable src und die neue Variable src gleich sind.

Stattdessen müssen Sie sicherstellen, dass jQuery die srcsetzt, nachdemdisplay:block angewendet wurde. Sie können setTimeout verwenden, um diesen Effekt zu erzielen:

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

Dadurch wird sichergestellt, dass srcgesetzt wird, nachdemdisplay:block auf das Element angewendet wurde.

Der Grund dafür ist, dass setTimeout die Funktion für die Ausführung von later in eine Warteschlange stellt (unabhängig davon, ob later länger ist), sodass die Funktion nicht mehr als Teil des aktuellen "Chunk" von JavaScript betrachtet wird und bereitstellt eine Lücke für Chrome, um zuerst den display:block zu rendern und anzuwenden, wodurch das Element sichtbar wird, bevor sein src-Attribut festgelegt ist.

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

Vielen Dank an #jquery von freenode IRC für die einfachere Antwort.


Alternativ können Sie ein erneutes Zeichnen erzwingen, um die Änderungen im Stapelformat zu leeren. Dies kann zum Beispiel durch Zugriff auf die offsetHeight -Eigenschaft des Elements erfolgen:

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

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

28
Kal

Die zuverlässigste Methode zum "Zurücksetzen" einer GIF ist das Anhängen einer zufälligen Abfragezeichenfolge. Dies bedeutet jedoch, dass die GIF jedes Mal erneut heruntergeladen wird. Stellen Sie daher sicher, dass es sich um eine kleine Datei handelt.

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

Diese Lösung lädt das GIF vorab und nimmt es aus dem Dom heraus und dann wieder in die src (damit ein erneuter Download vermieden wird)

Ich habe es gerade mit Jquery getestet, um das Attribut zu entfernen, und es funktioniert gut. 

Beispiel: 

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

Nur weil ich das immer noch brauche, dachte ich mir, dass die reine JS-Funktion, die ich verwende, für jemand anderen hilfreich sein könnte. Dies ist eine reine JS-Methode, um ein animiertes GIF neu zu starten, ohne es erneut zu laden. Sie können dies über ein Link- und/oder Dokumentladeereignis aufrufen.

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

Bei einigen Browsern müssen Sie lediglich die img.src auf sich selbst zurücksetzen, und es funktioniert einwandfrei. Auf IE müssen Sie es löschen, bevor Sie es zurücksetzen. Dieses resetGif () wählt den Bildnamen aus der Bild-ID. Dies ist praktisch, wenn Sie den tatsächlichen Image-Link für eine bestimmte ID ändern, da Sie nicht daran denken müssen, die resetGiF () - Aufrufe zu ändern.

--Nico

2
nico

Ich habe einen Button mit einem animierten No-Loop-Bild darin. Ich lade gerade das Image mit etwas Jquery auf und das scheint für mich zu funktionieren.

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

hier ist mein hack für hintergrundbilder:

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

Dies schien für mich in Chrome zu funktionieren, es wird jedes Mal ausgeführt, bevor ich das Bild einblende und löscht, dann den src wieder auffüllt und meine Animation beginnt jetzt jedes Mal von vorne.

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

Ich habe Probleme mit allen oben genannten Lösungen. Was schließlich funktioniert hat, war, das src vorübergehend durch ein transparentes 1px-Gif zu ersetzen:

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;
};
0
Daniel Howard

Es ist schon einige Jahre her und ich habe mich entschlossen, dies nochmals zu überdenken, da uns eine Reihe neuer Optionen zur Verfügung stehen.

Das Problem mit meiner vorherigen Antwort ist, dass die GIF jedes Mal neu geladen wird, wenn Sie sie neu starten möchten. Während dies für kleine Dateien in Ordnung ist, ist es dennoch ein Aufwand, der nach Möglichkeit vermieden werden sollte.

Aus diesem Grund habe ich eine neue Lösung, die AJAX verwendet, um die GIF einmal herunterzuladen, konvertiert sie dann in eine Daten-URL (über einen FileReader) und verwendet diese als Quelle mit einer angefügten zufälligen Abfragezeichenfolge .

Auf diese Weise lädt der Browser das Bild nur einmal herunter und kann es sogar ordnungsgemäß zwischenspeichern, und das "Zurücksetzen" wird von dieser vorab heruntergeladenen Ressource abgerufen.

Der einzige Haken ist natürlich, dass Sie sicherstellen müssen, dass er ordnungsgemäß geladen ist, bevor Sie ihn verwenden können.

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

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

Ich habe eine komplette Lösung für dieses Problem gefunden. Es kann hier gefunden werden: https://stackoverflow.com/a/31093916/1520422

Meine Lösung startet die Animation OHNE Neu laden der Bilddaten aus dem Netzwerk.

Es erzwingt auch, dass das Bild neu gezeichnet wird, um einige Malartefakte (in Chrom) zu korrigieren.

Ich bin auf diesen Thread gestoßen, nachdem ich viele andere gesucht hatte. Der Posten von David Bell führte mich zu der Lösung, die ich brauchte.

Ich dachte, ich würde meine Erfahrung posten, falls es für jeden nützlich sein könnte, der versucht, das zu erreichen, was ich wollte. Dies ist für eine HTML5/JavaScript/jQuery-Webanwendung, die über PhoneGap eine iPhone-Anwendung sein wird. Testen in Chrome.

Das Ziel:  

  1. Wenn der Benutzer auf die Schaltfläche A tippt/klickt, wird ein animiertes GIF angezeigt und abgespielt.
  2. Wenn der Benutzer auf die Schaltfläche B tippt/klickt, verschwindet GIF.
  3. Wenn der Benutzer erneut auf die Schaltfläche A tippt/klickt, sollte das animierte GIF nach dem Antippen/Klicken auf die Schaltfläche B erneut angezeigt und wiedergegeben werden.

Das Problem:

  • Beim Tippen/Klicken auf die Schaltfläche A fügte ich das GIF an ein vorhandenes Div an. Es würde gut spielen.
  • Beim Tippen/Klicken auf die Schaltfläche B versteckte ich dann den Container div und stellte dann die img src des Gifs auf eine leere Zeichenfolge (''). Wieder kein Problem (das heißt, das Problem war noch nicht offensichtlich.)
  • Dann tippte/klick auf Button A und nach Button/Klick auf Button B fügte ich den Pfad als src zum GIF hinzu.

    - Das hat nicht funktioniert. Das GIF würde bei nachfolgenden Antippen/Klicken von Button A angezeigt werden. Je mehr ich jedoch auf A geklickt/geklickt habe, desto mehr Male würde das Gif geladen und neu gestartet. Das heißt, wenn ich hin und her ging, dreimal auf Knopf A und dann auf Knopf B tippte/klicke, dann würde das Gif erscheinen und dann dreimal starten/stoppen/starten ... und meine ganze App begann zu chuggen. Ich denke, das Gif wurde mehrmals geladen, obwohl ich den src auf einen leeren String gesetzt hatte, als Button B gedrückt wurde.

Die Lösung:

Nachdem ich den Posten von David Bell angesehen hatte, kam ich zu meiner Antwort.

  1. Ich habe eine globale Variable definiert (nennen wir sie myVar), die den Container div und das Image (mit dem Quellpfad) enthält.
  2. Bei der Tipp/Klick-Funktion der Schaltfläche A habe ich das Container-Div an ein vorhandenes übergeordnetes Div im Dom angehängt.
  3. In dieser Funktion habe ich eine neue Variable erstellt, die den SRC-Pfad des GIF enthält.

Genau wie David vorgeschlagen hatte, tat ich das (plus ein Anhang):

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

DANN, habe ich in der Funktion für Button B die Quelle auf eine leere Zeichenfolge gesetzt und das div mit dem GIF entfernt:

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

Jetzt kann ich den Knopf A, dann den Knopf B, dann den Knopf A usw. den ganzen Tag lang antippen. Das GIF lädt und spielt auf Tap/Click von Button A, versteckt sich dann auf Tap/Click von Button B, lädt und spielt dann beim nächsten Antippen von Button A von Anfang an ohne Probleme.

0
Banjo Drill