Come posso determinare se un'immagine è stata caricata, utilizzando Javascript / jQuery?


84

Sto scrivendo un po 'di Javascript per ridimensionare l'immagine grande per adattarla alla finestra del browser dell'utente. (Purtroppo non controllo la dimensione delle immagini di origine.)

Quindi qualcosa del genere sarebbe nell'HTML:

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

C'è un modo per determinare se l' srcimmagine in un imgtag è stata scaricata?

Ne ho bisogno perché sto riscontrando un problema se $(document).ready()viene eseguito prima che il browser abbia caricato l'immagine. $("#photo").width()e $("#photo").height()restituirà la dimensione del segnaposto (il testo alternativo). Nel mio caso è qualcosa come 134 x 20.

In questo momento sto solo controllando se l'altezza della foto è inferiore a 150 e supponendo che in tal caso sia solo testo alternativo. Ma questo è un vero trucco, e si spezzerebbe se una foto è alta meno di 150 pixel (non probabile nel mio caso particolare), o se il testo alternativo è alto più di 150 pixel (potrebbe eventualmente accadere su una piccola finestra del browser) .


Modifica: per chiunque desideri vedere il codice:

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

});

Aggiornamento : grazie per i suggerimenti. Esiste il rischio che l'evento non venga attivato se imposto una richiamata per l' $("#photo").loadevento, quindi ho definito un evento onLoad direttamente sul tag immagine. Per la cronaca, ecco il codice con cui sono finito:

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

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

});

1
Questo è così vecchio e hai già accettato una risposta, quindi mi limiterò a commentare qui. Perché non puoi usare il plugin jQuery "onImagesLoad"? E inoltre, jQuery o no, cosa c'è di sbagliato nell'impostazione max-widthe max-heightnello stile dell'immagine con Javascript? Quindi eviti TUTTO il codice che hai bisogno di scrivere impostando la larghezza / altezza massima sulla dimensione della larghezza / altezza del riquadro di visualizzazione.

@ jon.wd7: non ho familiarità con quel plugin e potrebbe non essere stato in giro nel '08. per quanto riguarda max-width e max-height, due cose: 1) non sono supportati in IE (beh, non sono sicuro di IE 8); 2) se il viewport cambia le dimensioni (la finestra viene ridimensionata, ecc.), Avrei comunque bisogno di JavaScript per modificare la larghezza massima / altezza massima (anche se potrei non farlo se ho usato "100%" anziché una misurazione dei pixel)
Kip

È sicuramente supportato in IE7 e IE8, secondo quirksmode.org. Quindi non sono sicuro del tuo problema. Personalmente non supporto IE6 per piccole cose come questa, quindi quello che vedranno è la stessa cosa che vedrebbe un utente senza JS abilitato. E ovviamente dovresti reimpostare max-widthe max-heightridimensionare. Ma questo è un compito abbastanza facile, una riga che usa .resize()in effetti.

3
La proprietà complete fornisce il modo imperativo per sapere se l'immagine è stata caricata.
BorisOkunskiy

1
@Adrien, Mozilla ora mostra completo come supportato da tutti i principali browser, ad eccezione di Andoid (sconosciuto).
Oliver Bock

Risposte:


33

Aggiungi un listener di eventi o fai in modo che l'immagine si annunci con onload. Quindi calcola le dimensioni da lì.

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

Secondo le specifiche, onload è solo un evento per gli elementi del corpo e del frame; detto questo, penso che funzioni in IE, ma non so che funzioni in altri browser o che sia qualcosa che puoi presumere ... Stavo solo esaminando questo un paio di settimane fa ...
Jason Bunting il

L'ho testato in IE6, IE7, FF3, Opera9, Safair (Windows Beta) e Chrome (Windows Beta).
Kip

9
Il comportamento e il contenuto di confusione sono scoraggiati. Gli eventi devono essere applicati utilizzando Javascript, non in HTML.
dionyziz

10
Il suo commento è rilevante poiché non siamo bloccati nel 2008. La gente continua a leggere questo, e anche se non era considerato una cattiva pratica in 08, non vuoi che la gente pensi che sia una buona pratica ora.
Spoeken

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

14

Utilizzando l' archivio dati jquery è possibile definire uno stato "caricato".

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

Quindi altrove puoi fare:

if ($('#myimage').data('loaded')) {
    // loaded, so do stuff
}

2
Usa jQuery(this)invece di $(this)per una migliore compatibilità con altre librerie (jquery non possiede $), specialmente quando hai JavaScript in html.
John Magnolia

11

La risposta giusta è usare event.special.load

È possibile che l'evento di caricamento non venga attivato se l'immagine viene caricata dalla cache del browser. Per tenere conto di questa possibilità, possiamo utilizzare uno speciale evento di caricamento che si attiva immediatamente se l'immagine è pronta. event.special.load è attualmente disponibile come plugin.

Secondo i documenti su .load ()


2
Stavo per aggiungere una risposta con un suggerimento come questo, contento di aver visto questa risposta prima di codificarla. Fondamentalmente, i tuoi gestori devono prima controllare se l'immagine è caricata prima di impostare il gestore. Se è già caricato, attiva immediatamente la richiamata. È quello che $.readyfa. Stavo per suggerire di controllare solo la larghezza, ma ha i suoi problemi, mi piace molto quella soluzione.
Juan Mendes

5

Vuoi fare ciò che ha detto Allain, tuttavia tieni presente che a volte l'immagine viene caricata prima che sia pronto, il che significa che il tuo dispositivo di presa del carico non si attiverà. Il modo migliore è fare come dice Allain, ma impostare lo src dell'immagine con javascript dopo aver collegato la barra di caricamento. In questo modo puoi garantire che spari.

In termini di accessibilità, il tuo sito continuerà a funzionare per le persone senza javascript? Potresti voler dare al tag img il corretto src, collegare il tuo gestore dom ready per eseguire js: cancella l'immagine src (dagli un valore fisso con e altezza con css per evitare che la pagina sfarfallio), quindi imposta il tuo gestore di caricamento img, quindi reimpostare src al file corretto. In questo modo copri tutte le basi :)


Il sito funziona ancora per le persone senza Javascript, devono solo scorrere per vedere tutta l'immagine.
Kip

4

Come da uno dei commenti recenti alla tua domanda originale

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

Attenzione Questa risposta potrebbe causare un serio loop in ie8 e inferiori, perché img.complete non è sempre impostato correttamente dal browser. Se devi supportare ie8, usa un flag per ricordare che l'immagine è stata caricata.


Tienilo. Questa risposta potrebbe causare un serio loop in ie8 e inferiori, perché img.complete non è sempre impostato correttamente dal browser. Se devi supportare ie8, usa un flag per ricordare che l'immagine è stata caricata.
commonpike

2

Prova qualcosa come:

$("#photo").load(function() {
    alert("Hello from Image");
});

6
Grazie. Tuttavia, esiste la possibilità che l'immagine sia già stata caricata prima che ciò accada, nel qual caso l'evento di caricamento non verrebbe attivato.
Kip

Che ne dici di un tag script che imposta questo evento subito dopo il tag immagine? Il motivo per utilizzare ready è assicurarsi che l'intero documento sia caricato, il che non è necessario in questo caso, giusto?
Jason Goemaat,

2

Esiste un plug-in jQuery chiamato "imagesLoaded" che fornisce un metodo compatibile con tutti i browser per verificare se le immagini di un elemento sono state caricate.

Sito: https://github.com/desandro/imagesloaded/

Utilizzo per un contenitore che ha molte immagini all'interno:

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

Il plugin è fantastico:

  1. funziona per controllare un contenitore con molte immagini all'interno
  2. funziona per controllare un'immagine per vedere se è stata caricata

sembra un po 'pesante 5KB minimizzato solo per controllare img caricato. Dovrebbe essere disponibile un metodo più leggero più semplice ...
cdalxndr

1

Qualche commento su questo?

...

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

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

doShow();

...

Sembra che funzioni ovunque ...


è una cattiva pratica da usaresetTimeout
cdalxndr

1

Ho appena creato una funzione jQuery per caricare un'immagine utilizzando jQuerys Deferred Object che rende molto facile reagire all'evento di caricamento / errore:

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

Utilizzo:

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

Guardalo funzionare su: http://jsfiddle.net/roberkules/AdWZj/


Suona meraviglioso. Puoi fornire un esempio esatto di quando il tuo codice è preferibile a img.onload e img.onerror? Il tuo codice ha lo scopo solo di gestire le apparenti carenze della gestione degli errori di jQuery di cui sono stato appena informato: quell'errore non si attiva in IE se non c'è l'estensione del file?
mplungjan

un'idea interessante. quindi sapere quando l'immagine ha fatto è facile. Ma cosa succede se l'immagine non può essere caricata. Stavo cercando un modo per sapere se il caricamento dell'immagine non è riuscito. e mi hai dato l'idea del timeout durante il caricamento. +1 per quello
quercia

1
@oak il timeout dovrebbe essere solo un fallback. la maggior parte dei browser dovrebbe attivare un errorevento gestito da .error(function(e) { defer.rejectWith($img); }). Se guardi jsFiddle vedrai che il http://www.google.com/abc.png not foundtesto viene mostrato immediatamente nel riquadro dei risultati (senza attendere un timeout, perché l'evento di errore è scattato)
roberkules

nota che per jquery per sollevare .error due cose dovrebbero essere 1. l'handle ma essere impostato prima dell'errore sollevato. 2. .error gestisce solo il protocollo http e non il file: // quindi non riceverai errori lì ..
oak

nel mio esempio di codice il gestore di successo / errore viene impostato prima di assegnare l'attributo src esattamente per quel motivo. sulla file://restrizione: non ho mai avuto bisogno di collegare le immagini utilizzando il protocollo file e non credo che ce ne sia molto bisogno.
roberkules

1

Questa funzione controlla se un'immagine viene caricata in base alle dimensioni misurabili. Questa tecnica è utile se lo script viene eseguito dopo che alcune delle immagini sono già state caricate.

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

Ho scoperto che questa soluzione potrebbe richiedere che non vi siano margini o spaziatura interna sull'immagine e che venga fornito il testo alternativo di una stringa vuota. Nella maggior parte dei casi, però, funziona come previsto. Fallirà solo se la dimensione dell'immagine scaricata è maggiore di zero.
Ralph Ritoch

1

Ho trovato che questo ha funzionato per me

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

Il merito va totalmente a Frank Schwieterman, che ha commentato la risposta accettata. Ho dovuto metterlo qui, è troppo prezioso ...


0

Abbiamo sviluppato una pagina in cui caricava un certo numero di immagini e poi eseguivo altre funzioni solo dopo che l'immagine era stata caricata. Era un sito affollato che generava molto traffico. Sembra che il seguente semplice script abbia funzionato praticamente su tutti i browser:

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

MA QUESTO È UN POTENZIALE PROBLEMA PER IE9!

L'UNICO browser su cui abbiamo segnalato problemi è IE9. Non siamo sorpresi? Sembra che il modo migliore per risolvere il problema sia non assegnare un src all'immagine fino a DOPO che la funzione di onload è stata definita, in questo modo:

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

Sembra che IE 9 a volte non lancerà il file onload evento per qualsiasi motivo. Altre soluzioni in questa pagina (come quella di Evan Carroll, per esempio) ancora non funzionavano. Logicamente, questo ha verificato se lo stato di caricamento era già riuscito e ha attivato la funzione e, in caso contrario, ha impostato il gestore onload, ma anche quando lo fai abbiamo dimostrato durante i test che l'immagine potrebbe caricarsi tra quelle due righe di js in tal modo che appare non caricato nella prima riga e quindi viene caricato prima che venga impostato il gestore onload.

Abbiamo scoperto che il modo migliore per ottenere ciò che desideri è non definire l'SRC dell'immagine finché non hai impostato il onloadtrigger dell'evento.

Abbiamo solo recentemente smesso di supportare IE8, quindi non posso parlare di versioni precedenti a IE9, altrimenti, tra tutti gli altri browser utilizzati sul sito: IE10 e 11, nonché Firefox, Chrome, Opera, Safari e altro browser per dispositivi mobili che le persone utilizzavano: impostare srcprima di assegnare il onloadgestore non era nemmeno un problema.


0

Posso suggerire del tutto una soluzione CSS pura?

Devi solo avere un Div in cui vuoi mostrare l'immagine. Imposta l'immagine come sfondo. Quindi avere la proprietà background-size: covero in background-size: containbase a come la desideri.

coverritaglierà l'immagine fino a quando i lati più piccoli coprono la scatola. containmanterrà l'intera immagine all'interno del div, lasciandoti degli spazi ai lati.

Controlla lo snippet di seguito.

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>


0

Trovo che questa semplice soluzione funzioni meglio per me:

        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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.