Jak utworzyć wywołanie zwrotne JavaScript, aby wiedzieć, kiedy ładowany jest obraz?

136

Chcę wiedzieć, kiedy obraz się załadował. Czy można to zrobić za pomocą oddzwonienia?

Jeśli nie, to czy w ogóle jest na to sposób?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
2
github.com/desandro/imagesloaded - ludzie, sprawdź ten pakiet.
mangatinanda

Odpowiedzi:

159

.complete + oddzwonienie

Jest to metoda zgodna ze standardami bez dodatkowych zależności i czeka nie dłużej niż to konieczne:

var img = document.querySelector('img')

function loaded() {
  alert('loaded')
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener('load', loaded)
  img.addEventListener('error', function() {
      alert('error')
  })
}

Źródło: http://www.html5rocks.com/en/tutorials/es6/promises/

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
4
Czy to może się nie udać, jeśli obraz jest wyświetlany między img.completewywołaniem a addEventListenerwywołaniem?
Thomas Ahle,
@ThomasAhle Nie jestem ekspertem, ale wydaje się to możliwe. Zobaczmy, czy ktoś ma rozwiązanie.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Chyba byłoby tylko kwestią dla kodu równoległego, który najbardziej JavaScript prawdopodobnie nie jest ..
Thomas Ahle
4
@ThomasAhle Nie można, ponieważ przeglądarka uruchomi zdarzenie load tylko wtedy, gdy kolejka zdarzeń zostanie uruchomiona. To powiedziawszy, loaddetektor zdarzenia musi znajdować się w elseklauzuli, co img.completemoże stać się prawdą zanim loadzdarzenie zostanie uruchomione , więc gdyby tak nie było, mógłbyś potencjalnie loadedzadzwonić dwukrotnie (zauważ, że jest to stosunkowo prawdopodobne, że zmieni się tak, że stanie img.completesię prawdą tylko wtedy, gdy zdarzenie pożary).
gsnedders,
72

Image.onload () często działa.

Aby go użyć, musisz upewnić się, że powiązałeś program obsługi zdarzeń przed ustawieniem atrybutu src.

Powiązane linki:

Przykładowe zastosowanie:

    window.onload = function () {

        var logo = document.getElementById('sologo');

        logo.onload = function () {
            alert ("The image has loaded!");		
        };

        setTimeout(function(){
            logo.src = 'https://edmullen.net/test/rc.jpg';         
        }, 5000);
    };
 <html>
    <head>
    <title>Image onload()</title>
    </head>
    <body>

    <img src="#" alt="This image is going to load" id="sologo"/>

    <script type="text/javascript">

    </script>
    </body>
    </html>

keparo
źródło
26
FYI: Zgodnie ze specyfikacją W3C, onload nie jest prawidłowym zdarzeniem dla elementów IMG. Oczywiście przeglądarki to obsługują, ale jeśli zależy Ci na specyfikacji i nie masz 100% pewności, że obsługują ją wszystkie przeglądarki, na które chcesz kierować reklamy, możesz to przemyśleć lub przynajmniej pamiętać o tym.
Jason Bunting
3
dlaczego czekanie 5 sekund na ustawienie źródła wydaje się złym pomysłem?
quemeful
8
@quemeful, dlatego nazywa się to „przykładem”.
Diego Jancic
3
@JasonBunting Na co patrzysz, co sprawia, że ​​uważasz, że loadwydarzenie jest nieważne? html.spec.whatwg.org/multipage/webappapis.html#handler-onload to definicja modułu onload obsługi zdarzeń.
gsnedders,
4
@gsnedders - zdajesz sobie sprawę, zakładam, że kiedy pisałem ten komentarz, miałem na myśli istniejący standard, a nie ten, na który wskazałeś, który jest o 4,5 roku nowszy. Gdybym wtedy zapytał, mógłbym na to wskazać. Taka jest natura sieci, prawda? Rzeczy się starzeją, są przenoszone, modyfikowane itp.
Jason Bunting
20

Możesz użyć właściwości .complete klasy obrazu Javascript.

Mam aplikację, w której przechowuję wiele obiektów Image w tablicy, która będzie dynamicznie dodawana do ekranu, a gdy się ładują, piszę aktualizacje do innego div na stronie. Oto fragment kodu:

var gAllImages = [];

function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
    gAllImages = [];

    for (var i = thumbnailsBegin; i < thumbnailsEnd; i++) 
    {
        var theImage = new Image();
        theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
        gAllImages.push(theImage);

        setTimeout('checkForAllImagesLoaded()', 5);
        window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;

        // make a new div containing that image
        makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
    }
}

function checkForAllImagesLoaded()
{
    for (var i = 0; i < gAllImages.length; i++) {
        if (!gAllImages[i].complete) {
            var percentage = i * 100.0 / (gAllImages.length);
            percentage = percentage.toFixed(0).toString() + ' %';

            userMessagesController.setMessage("loading... " + percentage);
            setTimeout('checkForAllImagesLoaded()', 20);
            return;
        }
    }

    userMessagesController.setMessage(globals.defaultTitle);
}
Jon DellOro
źródło
Wcześniej używałem podobnego kodu w mojej pracy. Działa to dobrze we wszystkich przeglądarkach.
Gabriel Hurley
2
Problem z sprawdzaniem ukończenia polega na tym, że począwszy od IE9 zdarzenia OnLoad są uruchamiane przed załadowaniem wszystkich obrazów i trudno jest teraz znaleźć wyzwalacz dla funkcji sprawdzającej.
Gene Vincent
8

Życie jest za krótkie dla jQuery.

function waitForImageToLoad(imageElement){
  return new Promise(resolve=>{imageElement.onload = resolve})
}

var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"

myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
  // Image have loaded.
  console.log('Loaded lol')
});
<img id="myImage" src="">

Idan Beker
źródło
1
To świetna odpowiedź, ale myślę, że nie potrzebujesz nawet tyle kodu. Po prostu sprawiasz, że wygląda to zagmatwane, dodając za srcpomocą JS.
Brandon Benefield
1
Czas jest ogromnym ograniczeniem w programowaniu. Z mojego doświadczenia wynika, że ​​pisanie czytelnego (choć czasami długiego) kodu daje ogromne korzyści czasowe.
Idan Beker
Dlaczego miałbyś przechowywać src w nowej zmiennej tylko po to, aby zużywać je w następnej linii? Jeśli celem jest zwięzłość, jest to anty-wzór. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620Zrób sztuczkę.
Josiah,
3

Oto odpowiednik jQuery:

var $img = $('img');

if ($img.length > 0 && !$img.get(0).complete) {
   $img.on('load', triggerAction);
}

function triggerAction() {
   alert('img has been loaded');
}
Alexander Drobyshevsky
źródło
1

Nie nadaje się na rok 2008, kiedy zadano pytanie, ale obecnie działa to dobrze:

async function newImageSrc(src) {
  // Get a reference to the image in whatever way suits.
  let image = document.getElementById('image-id');

  // Update the source.
  img.src = src;

  // Wait for it to load.
  await new Promise((resolve) => { image.onload = resolve; });

  // Done!
  console.log('image loaded! do something...');
}
Hugh
źródło
0

te funkcje rozwiążą problem, musisz zaimplementować DrawThumbnailsfunkcję i mieć zmienną globalną do przechowywania obrazów. Uwielbiam to, aby działało z obiektem klasy, który ma ThumbnailImageArrayzmienną składową, ale mam problemy!

zadzwonił jak w addThumbnailImages(10);

var ThumbnailImageArray = [];

function addThumbnailImages(MaxNumberOfImages)
{
    var imgs = [];

    for (var i=1; i<MaxNumberOfImages; i++)
    {
        imgs.push(i+".jpeg");
    }

    preloadimages(imgs).done(function (images){
            var c=0;

            for(var i=0; i<images.length; i++)
            {
                if(images[i].width >0) 
                {
                    if(c != i)
                        images[c] = images[i];
                    c++;
                }
            }

            images.length = c;

            DrawThumbnails();
        });
}



function preloadimages(arr)
{
    var loadedimages=0
    var postaction=function(){}
    var arr=(typeof arr!="object")? [arr] : arr

    function imageloadpost()
    {
        loadedimages++;
        if (loadedimages==arr.length)
        {
            postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
        }
    };

    for (var i=0; i<arr.length; i++)
    {
        ThumbnailImageArray[i]=new Image();
        ThumbnailImageArray[i].src=arr[i];
        ThumbnailImageArray[i].onload=function(){ imageloadpost();};
        ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
    }
    //return blank object with done() method    
    //remember user defined callback functions to be called when images load
    return  { done:function(f){ postaction=f || postaction } };
}
dave
źródło
11
Większość tego kodu jest nieistotna, w tym cała addThumbnailImagesfunkcja. Zmniejsz to do odpowiedniego kodu, a usunę -1.
Justin Morgan
0

Jeśli celem jest nadanie stylu img po wyrenderowaniu obrazu przez przeglądarkę, należy:

const img = new Image();
img.src = 'path/to/img.jpg';

img.decode().then(() => {
/* set styles */
/* add img to DOM */ 
});

ponieważ najpierw przeglądarka loads the compressed version of image, potem na decodes itkońcu paints. ponieważ nie ma zdarzenia, dla paintktórego należy uruchomić logikę po tym, jak przeglądarka ma decodedtag img.

Sajad
źródło
-2

Jeśli używasz React.js, możesz to zrobić:

render() {

// ...

<img 
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}

src={item.src} key={item.key}
ref={item.key} />

// ...}

Gdzie:

  • - onLoad (...) teraz wywoła coś takiego: {src: " https: //......png ", key: "1"} możesz użyć tego jako "klucza", aby dowiedzieć się, które obrazy jest poprawnie załadowany, a który nie.
  • - onError (...) to jest to samo, ale dla błędów.
  • - obiekt "item" to coś takiego {klucz: "..", src: ".."}, którego możesz użyć do przechowywania adresu URL i klucza obrazków, aby użyć ich w liście obrazów.

  • Mikrofon
    źródło