Wie kann ich mithilfe von Javascript / jQuery feststellen, ob ein Bild geladen wurde?

84

Ich schreibe etwas Javascript, um die Größe des großen Bildes so zu ändern, dass es in das Browserfenster des Benutzers passt. (Ich kontrolliere leider nicht die Größe der Quellbilder.)

So etwas wäre also im HTML:

<img id="photo"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Kann ich feststellen, ob das srcBild in einem imgTag heruntergeladen wurde?

Ich brauche das, weil ich auf ein Problem stoße, wenn $(document).ready()es ausgeführt wird, bevor der Browser das Bild geladen hat. $("#photo").width()und $("#photo").height()gibt die Größe des Platzhalters (den Alternativtext) zurück. In meinem Fall ist das ungefähr 134 x 20.

Im Moment überprüfe ich nur, ob die Höhe des Fotos weniger als 150 beträgt, und gehe davon aus, dass es sich in diesem Fall nur um Alternativtext handelt. Dies ist jedoch ein ziemlicher Hack, und es würde brechen, wenn ein Foto weniger als 150 Pixel hoch ist (in meinem speziellen Fall nicht wahrscheinlich) oder wenn der Alternativtext mehr als 150 Pixel hoch ist (möglicherweise in einem kleinen Browserfenster). .


Bearbeiten: Für alle, die den Code sehen möchten:

$(function()
{
  var REAL_WIDTH = $("#photo").width();
  var REAL_HEIGHT = $("#photo").height();

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(REAL_HEIGHT < 150)
    {
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
      if(REAL_HEIGHT < 150)
      {
        //image not loaded.. try again in a quarter-second
        setTimeout(adjust_photo_size, 250);
        return;
      }
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});

Update : Danke für die Vorschläge. Es besteht die Gefahr, dass das Ereignis nicht ausgelöst wird, wenn ich einen Rückruf für das $("#photo").loadEreignis festlege. Daher habe ich ein onLoad-Ereignis direkt auf dem Image-Tag definiert. Für die Aufzeichnung ist hier der Code, mit dem ich am Ende gegangen bin:

<img id="photo"
     onload="photoLoaded();"
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />

Dann in Javascript:

//This must be outside $() because it may get called first
var isPhotoLoaded = false;
function photoLoaded()
{
  isPhotoLoaded = true;
}

$(function()
{
  //Hides scrollbars, so we can resize properly.  Set with JS instead of
  //  CSS so that page doesn't break with JS disabled.
  $("body").css("overflow", "hidden");

  var REAL_WIDTH = -1;
  var REAL_HEIGHT = -1;

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()
  {
    if(!isPhotoLoaded)
    {
      //image not loaded.. try again in a quarter-second
      setTimeout(adjust_photo_size, 250);
      return;
    }
    else if(REAL_WIDTH < 0)
    {
      //first time in this function since photo loaded
      REAL_WIDTH = $("#photo").width();
      REAL_HEIGHT = $("#photo").height();
    }

    var new_width = . . . ;
    var new_height = . . . ;

    $("#photo").width(Math.round(new_width));
    $("#photo").height(Math.round(new_height));
  }

});
Pennen
quelle
1
Das ist so alt und du hast bereits eine Antwort akzeptiert, also werde ich hier nur einen Kommentar abgeben. Warum können Sie das jQuery-Plugin 'onImagesLoad' nicht verwenden? Und auch, jQuery oder nicht, was ist falsch an der Einstellung max-widthund max-heightam Bildstil mit Javascript? Sie vermeiden dann den gesamten Code, den Sie schreiben müssen, indem Sie die maximale Breite / Höhe auf die Größe der Breite / Höhe des Ansichtsfensters einstellen.
@ jon.wd7: Ich bin mit diesem Plugin nicht vertraut und es gab es möglicherweise noch nicht in '08. Was die maximale Breite und die maximale Höhe betrifft, zwei Dinge: 1) Sie werden im IE nicht unterstützt (nun, ich bin mir bei IE 8 nicht sicher). 2) Wenn sich die Größe des Ansichtsfensters ändert (die Größe des Fensters wird geändert usw.), benötige ich immer noch Javascript, um die maximale Breite / Höhe zu ändern (obwohl dies möglicherweise nicht der Fall ist, wenn ich "100%" anstelle einer Pixelmessung verwendet habe).
Kip
Laut quirksmode.org wird es definitiv in IE7 und IE8 unterstützt. Ich bin mir also Ihres Problems nicht sicher. Ich persönlich unterstütze IE6 für solche kleinen Dinge nicht. Sie sehen also dasselbe, was ein Benutzer ohne aktiviertes JS sehen würde. Und natürlich müssten Sie die Größe zurücksetzen max-widthund max-heightändern. Aber das ist eine ziemlich einfache Aufgabe, die ein Einzeiler .resize()tatsächlich verwendet.
3
Die vollständige Eigenschaft gibt die zwingende Möglichkeit zu wissen, ob das Bild geladen wurde.
BorisOkunskiy
1
@Adrien, Mozilla jetzt zeigt vollständig wie von allen gängigen Browsern unterstützt, mit Ausnahme von Andoid (unbekannt).
Oliver Bock

Antworten:

32

Fügen Sie entweder einen Ereignis-Listener hinzu oder lassen Sie das Bild sich beim Laden anmelden. Dann finden Sie die Abmessungen von dort heraus.

<img id="photo"
     onload='loaded(this.id)'
     src="a_really_big_file.jpg"
     alt="this is some alt text"
     title="this is some title text" />
Diodeus - James MacFarlane
quelle
Laut Spezifikation ist Onload nur ein Ereignis für die Body- und Frameset-Elemente. Das heißt, ich denke, das funktioniert im IE, aber ich weiß nicht, dass es in anderen Browsern funktioniert oder dass es etwas ist, von dem Sie annehmen können ... Ich habe mich erst vor ein paar Wochen damit befasst ...
Jason Ammer
Ich habe es in IE6, IE7, FF3, Opera9, Safair (Windows Beta) und Chrome (Windows Beta) getestet.
Kip
9
Messing Verhalten und Inhalt wird entmutigt. Ereignisse sollten mit Javascript und nicht in HTML angewendet werden.
Dionyziz
10
Sein Kommentar ist relevant, da wir 2008 nicht feststecken. Die Leute lesen dies immer noch, und obwohl es 08 nicht als schlechte Praxis angesehen wurde, möchten Sie nicht, dass die Leute jetzt über seine gute Praxis nachdenken.
Spoeken
3
document.querySelector ("img"). addEventListener ("load", function () {alert ('onload!');});
Frank Schwieterman
14

Mit dem jquery-Datenspeicher können Sie einen 'geladenen' Status definieren.

<img id="myimage" onload="$(this).data('loaded', 'loaded');" src="lolcats.jpg" />

Dann können Sie anderswo tun:

if ($('#myimage').data('loaded')) {
    // loaded, so do stuff
}
Mike Fogel
quelle
2
Verwenden Sie jQuery(this)statt $(this)für eine bessere Kompatibilität mit anderen Bibliotheken (jquery besitzt das $ nicht), insbesondere wenn Sie JavaScript in HTML haben.
John Magnolia
11

Die richtige Antwort ist die Verwendung von event.special.load

Es ist möglich, dass das Ladeereignis nicht ausgelöst wird, wenn das Bild aus dem Browser-Cache geladen wird. Um diese Möglichkeit zu berücksichtigen, können wir ein spezielles Ladeereignis verwenden, das sofort ausgelöst wird, wenn das Image bereit ist. event.special.load ist derzeit als Plugin verfügbar.

Gemäß den Dokumenten auf .load ()

Evan Carroll
quelle
2
Ich wollte eine Antwort mit einem Vorschlag wie diesem hinzufügen, froh, dass ich diese Antwort gesehen habe, bevor ich sie codiert habe. Grundsätzlich müssen Ihre Handler zuerst prüfen, ob das Bild geladen ist, bevor Sie den Handler einstellen. Wenn es bereits geladen ist, lösen Sie den Rückruf sofort aus. Es ist was $.readytut. Ich wollte vorschlagen, nur die Breite zu überprüfen, aber das hat seine Probleme, ich mag diese Lösung wirklich.
Juan Mendes
5

Sie möchten das tun, was Allain gesagt hat. Beachten Sie jedoch, dass das Image manchmal geladen wird, bevor dom ready ist. Dies bedeutet, dass Ihr Load-Handler nicht ausgelöst wird. Der beste Weg ist, wie Allain sagt, aber den src des Bildes mit Javascript zu setzen, nachdem Sie den Load Hander angebracht haben. Auf diese Weise können Sie sicherstellen, dass es ausgelöst wird.

Funktioniert Ihre Website in Bezug auf die Barrierefreiheit weiterhin für Personen ohne Javascript? Möglicherweise möchten Sie dem img-Tag den richtigen src zuweisen, Ihren dom ready-Handler anhängen, um Ihr js auszuführen: Löschen Sie den Bild-src (geben Sie ihm eine feste Höhe und Höhe mit css, um das Flackern der Seite zu verhindern) und stellen Sie dann Ihren img-Ladehandler ein. Setzen Sie dann den Quellcode auf die richtige Datei zurück. Auf diese Weise decken Sie alle Basen ab :)

Andrew Bullock
quelle
Die Seite funktioniert immer noch für Leute ohne Javascript. Sie müssen nur scrollen, um das gesamte Bild zu sehen.
Kip
4

Gemäß einem der letzten Kommentare zu Ihrer ursprünglichen Frage

$(function() {

  $(window).resize(adjust_photo_size);
  adjust_photo_size();

  function adjust_photo_size()  {
    if (!$("#photo").get(0).complete) {
       $("#photo").load(function() {
          adjust_photo_size();
       });
    } else {
      ... 
    }
});

Warnung Diese Antwort kann zu einer schwerwiegenden Schleife in ie8 und niedriger führen, da img.complete vom Browser nicht immer richtig eingestellt wird. Wenn Sie ie8 unterstützen müssen, verwenden Sie ein Flag, um sich daran zu erinnern, dass das Bild geladen ist.

Commonpike
quelle
Halte es. Diese Antwort kann eine ernsthafte Schleife in ie8 und niedriger verursachen, da img.complete vom Browser nicht immer richtig eingestellt wird. Wenn Sie ie8 unterstützen müssen, verwenden Sie ein Flag, um sich daran zu erinnern, dass das Bild geladen ist.
Commonpike
2

Versuchen Sie etwas wie:

$("#photo").load(function() {
    alert("Hello from Image");
});
Allain Lalonde
quelle
6
Vielen Dank. Es besteht jedoch die Möglichkeit, dass das Image bereits geladen wurde, bevor dies geschieht. In diesem Fall wird das Ladeereignis nicht ausgelöst.
Kip
Wie wäre es mit einem Skript-Tag, das dieses Ereignis direkt nach dem Bild-Tag festlegt? Der Grund für die Verwendung von ready besteht darin, sicherzustellen, dass das gesamte Dokument geladen ist, was in diesem Fall nicht erforderlich ist, oder?
Jason Goemaat
2

Es gibt ein jQuery-Plugin namens "imagesLoaded", das eine browserübergreifende Methode bietet, um zu überprüfen, ob die Bilder eines Elements geladen wurden.

Seite? ˅: https://github.com/desandro/imagesloaded/

Verwendung für einen Container mit vielen Bildern:

$('container').imagesLoaded(function(){
 console.log("I loaded!");
})

Das Plugin ist großartig:

  1. funktioniert zum Überprüfen eines Containers mit vielen Bildern
  2. Funktioniert, um ein IMG zu überprüfen, um festzustellen, ob es geladen wurde
Jay
quelle
scheint ein bisschen schwer zu sein 5KB minimiert nur um zu überprüfen, ob img geladen ist. Sollte eine einfachere und leichtere Methode verfügbar sein ...
cdalxndr
1

Irgendwelche Kommentare zu diesem?

...

doShow = function(){
  if($('#img_id').attr('complete')){
    alert('Image is loaded!');
  } else {
    window.setTimeout('doShow()',100);
  }
};

$('#img_id').attr('src','image.jpg');

doShow();

...

Scheint überall zu funktionieren ...

Jay
quelle
Es ist eine schlechte PraxissetTimeout
cdalxndr
1

Ich habe gerade eine jQuery-Funktion erstellt, um ein Bild mit jQuerys Deferred Object zu laden , wodurch es sehr einfach ist, auf Lade- / Fehlerereignisse zu reagieren:

$.fn.extend({
    loadImg: function(url, timeout) {
        // init deferred object
        var defer = $.Deferred(),
            $img = this,
            img = $img.get(0),
            timer = null;

        // define load and error events BEFORE setting the src
        // otherwise IE might fire the event before listening to it
        $img.load(function(e) {
            var that = this;
            // defer this check in order to let IE catch the right image size
            window.setTimeout(function() {
                // make sure the width and height are > 0
                ((that.width > 0 && that.height > 0) ? 
                    defer.resolveWith : 
                    defer.rejectWith)($img);
            }, 1);
        }).error(function(e) {
            defer.rejectWith($img);
        });

        // start loading the image
        img.src = url;

        // check if it's already in the cache
        if (img.complete) {
            defer.resolveWith($img);
        } else if (0 !== timeout) {
            // add a timeout, by default 15 seconds
            timer = window.setTimeout(function() {
                defer.rejectWith($img);
            }, timeout || 15000);
        }

        // return the promise of the deferred object
        return defer.promise().always(function() {
            // stop the timeout timer
            window.clearTimeout(timer);
            timer = null;
            // unbind the load and error event
            this.off("load error");
        });
    }
});

Verwendung:

var image = $('<img />').loadImg('http://www.google.com/intl/en_com/images/srpr/logo3w.png')
.done(function() {
    alert('image loaded');
    $('body').append(this);
}).fail(function(){
    alert('image failed');
});

Siehe es funktioniert unter: http://jsfiddle.net/roberkules/AdWZj/

Roberkules
quelle
Das hört sich wunderbar an. Können Sie bitte ein genaues Beispiel geben, wann Ihr Code img.onload und img.onerror vorzuziehen ist? Ist Ihr Code nur dazu gedacht, die scheinbaren Mängel der jQuery-Fehlerbehandlung zu beheben, über die ich gerade informiert wurde: Dieser Fehler wird im IE nicht ausgelöst, wenn keine Dateierweiterung vorhanden ist?
Mplungjan
interessante Idee. Es ist also einfach zu wissen, wann das Bild fertig ist. Was aber, wenn das Bild nicht geladen werden konnte? Ich habe nach einer Möglichkeit gesucht, um festzustellen, ob das Laden des Bildes fehlgeschlagen ist. und du hast mir die Idee gegeben, beim Laden eine Zeitüberschreitung zu verursachen. +1 dafür
Eiche
1
@oak das Timeout sollte nur ein Fallback sein. Die meisten Browser sollten ein errorEreignis auslösen, das von behandelt wird .error(function(e) { defer.rejectWith($img); }). Wenn Sie sich die jsFiddle ansehen, werden Sie sehen, dass der http://www.google.com/abc.png not foundText sofort im Ergebnisbereich angezeigt wird (ohne auf eine Zeitüberschreitung zu warten, da das Fehlerereignis
eingetreten ist
Beachten Sie, dass für jquery zum Auslösen von .error zwei Dinge 1. das Handle sein sollten, aber vor dem ausgelösten Fehler gesetzt werden müssen. 2. .error behandelt nur das http-Protokoll und nicht die Datei: //, damit dort kein Fehler auftritt.
Eiche
In meinem Codebeispiel werden die Erfolgs- / Fehlerbehandlungsroutinen festgelegt, bevor das src-Attribut genau aus diesem Grund zugewiesen wird. Über die file://Einschränkung - Ich musste nie Bilder mit dem Dateiprotokoll verknüpfen, und ich glaube nicht, dass es einen großen Bedarf gibt.
Roberkules
1

Diese Funktion prüft anhand messbarer Abmessungen, ob ein Bild geladen wird. Diese Technik ist nützlich, wenn Ihr Skript ausgeführt wird, nachdem einige der Bilder bereits geladen wurden.

imageLoaded = function(node) {
    var w = 'undefined' != typeof node.clientWidth ? node.clientWidth : node.offsetWidth;
    var h = 'undefined' != typeof node.clientHeight ? node.clientHeight : node.offsetHeight;
    return w+h > 0 ? true : false;
};
Ralph Ritoch
quelle
Ich habe festgestellt, dass für diese Lösung möglicherweise kein Rand oder Abstand im Bild vorhanden sein muss und dass Alternativtext einer leeren Zeichenfolge bereitgestellt wird. In den meisten Fällen funktioniert es jedoch wie vorgesehen. Dies schlägt nur fehl, wenn das entladene Bild größer als Null ist.
Ralph Ritoch
1

Ich fand das funktionierte für mich

document.querySelector("img").addEventListener("load", function() { alert('onload!'); });

Der Kredit geht insgesamt an Frank Schwieterman, der die akzeptierte Antwort kommentierte. Ich musste das hier setzen, es ist zu wertvoll ...

Armand
quelle
0

Wir haben eine Seite entwickelt, auf der eine Reihe von Bildern geladen wurden, und andere Funktionen erst ausgeführt, nachdem das Bild geladen wurde. Es war eine geschäftige Site, die viel Verkehr erzeugte. Es scheint, dass das folgende einfache Skript in praktisch allen Browsern funktioniert hat:

$(elem).onload = function() {
    doSomething();
}

ABER DAS IST EIN POTENZIELLES PROBLEM FÜR IE9!

Der EINZIGE Browser, in dem wir Probleme gemeldet hatten, ist IE9. Sind wir nicht überrascht? Es scheint, dass der beste Weg, um das Problem zu lösen, darin besteht, dem Bild erst dann einen src zuzuweisen, wenn die Onload-Funktion wie folgt definiert wurde:

$(elem).onload = function() {
    doSomething();
}
$(elem).attr('src','theimage.png');

Es scheint, dass IE 9 manchmal nicht werfen wird onload Ereignis aus irgendeinem Grund . Andere Lösungen auf dieser Seite (wie zum Beispiel die von Evan Carroll) funktionierten immer noch nicht. Dies überprüfte logischerweise, ob der Ladezustand bereits erfolgreich war und löste die Funktion aus, und wenn dies nicht der Fall war, stellte der Onload-Handler ein, aber selbst wenn Sie dies tun, haben wir beim Testen gezeigt, dass das Bild dadurch zwischen diesen beiden Zeilen von js geladen werden kann erscheint nicht in die erste Zeile geladen und wird dann geladen, bevor der Onload-Handler gesetzt wird.

Wir haben festgestellt, dass der beste Weg, um das zu bekommen, was Sie wollen, darin besteht, den src des Bildes erst zu definieren, wenn Sie den onloadEreignisauslöser gesetzt haben.

Wir haben erst kürzlich die Unterstützung von IE8 eingestellt, daher kann ich nicht für Versionen vor IE9 sprechen, ansonsten nicht für alle anderen Browser, die auf der Website verwendet wurden - IE10 und 11 sowie Firefox, Chrome, Opera, Safari und was auch immer Benutzer von mobilen Browsern verwendeten - das Einstellen srcvor dem Zuweisen des onloadHandlers war nicht einmal ein Problem.

Tintenfisch
quelle
0

Darf ich insgesamt eine reine CSS-Lösung vorschlagen?

Haben Sie einfach eine Div, in der Sie das Bild anzeigen möchten. Legen Sie das Bild als Hintergrund fest. Dann haben Sie die Eigenschaft background-size: coveroder background-size: containje nachdem, wie Sie es wollen.

coverschneidet das Bild zu, bis kleinere Seiten die Box bedecken. containbehält das gesamte Bild im div bei und hinterlässt Leerzeichen an den Seiten.

Überprüfen Sie das Snippet unten.

div {
  height: 300px;
  width: 300px;
  border: 3px dashed grey;
  background-position: center;
  background-repeat: no-repeat;
}

.cover-image {
  background-size: cover;
}

.contain-image {
  background-size: contain;
}
<div class="cover-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
<br/>
<div class="contain-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>

arunwithasmile
quelle
0

Ich finde, dass diese einfache Lösung am besten für mich funktioniert:

        function setEqualHeight(a, b) {
            if (!$(a).height()) {
                return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
            }
            $(b).height($(a).height());
        }

        $(document).ready(function() {
            setEqualHeight('#image', '#description');
            $(window).resize(function(){setEqualHeight('#image', '#description')});
        });
    </script>
Martin Francis
quelle