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


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/


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>


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

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


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

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

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

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.


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

  • Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
    Licensed under cc by-sa 3.0 with attribution required.