Как создать обратный вызов JavaScript, чтобы узнать, когда изображение загружается?

136

Я хочу знать, когда изображение закончило загрузку. Есть ли способ сделать это с помощью обратного вызова?

Если нет, есть ли способ сделать это вообще?

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
2
github.com/desandro/imagesloaded - ребята, проверьте этот пакет.
Мангатинанда

Ответы:

159

.complete + обратный звонок

Это совместимый со стандартами метод без дополнительных зависимостей, который ожидает не дольше, чем необходимо:

var img = document.querySelector('img')

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

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

Источник: http://www.html5rocks.com/en/tutorials/es6/promises/

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
4
Может ли это пойти не так, если изображение завершится между img.completeвызовом и addEventListenerвызовом?
Томас Але
@ThomasAhle Я не эксперт, но это кажется возможным. Посмотрим, есть ли у кого-нибудь решение.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
Я предполагаю, что это будет проблемой только для параллельного кода, который, скорее всего, нет в большинстве javascript ..
Томас Але
4
@ThomasAhle Не может, потому что браузер будет запускать событие загрузки только тогда, когда очередь событий вращается. Тем не менее, loadслушатель события должен быть в elseпредложении, что img.completeможет стать истинным до того, как loadсобытие будет запущено, следовательно, если бы это было не так, вы могли бы потенциально вызвать loadedдважды (обратите внимание, что это относительно вероятно изменится так, что img.completeстанет истинным только тогда, когда событие пожары).
gsnedders
72

Image.onload () будет часто работать.

Чтобы использовать его, вам нужно обязательно связать обработчик событий, прежде чем устанавливать атрибут src.

Ссылки по теме:

Пример использования:

    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
источник
26
К вашему сведению: согласно спецификации W3C, onload не является допустимым событием для элементов IMG. Очевидно, что браузеры поддерживают его, но если вы заботитесь о спецификации и не уверены на 100%, что все браузеры, для которых вы хотите настроить таргетинг, поддерживают это, вы можете переосмыслить или, по крайней мере, помнить об этом.
Джейсон Бантинг
3
почему ожидание 5 секунд для установки источника кажется плохой идеей?
унылый
8
@quemeful, поэтому это называется «пример».
Диего Янчич
3
@JasonBunting То, на что вы смотрите, заставляет вас думать, что loadмероприятие недействительно? html.spec.whatwg.org/multipage/webappapis.html#handler-onload - это определение onload обработчика событий.
gsnedders
4
@gsnedders - вы понимаете, я предполагаю, что когда я писал этот комментарий, я имел в виду существующий стандарт, а не тот, на который вы указали, который на 4,5 года новее. Если бы вы спросили тогда, я мог бы указать на это, возможно. Такова природа сети, верно? Вещи стареют или перемещаются или модифицируются и т. Д.
Джейсон Бантинг
20

Вы можете использовать свойство .complete класса изображений Javascript.

У меня есть приложение, в котором я храню несколько объектов Image в массиве, которые будут динамически добавляться на экран, и по мере их загрузки я записываю обновления в другой div на странице. Вот фрагмент кода:

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);
}
Джон Деллоро
источник
Я использовал подобный код в моей работе раньше. Это хорошо работает во всех браузерах.
Габриэль Херли
2
Проблема с проверкой завершена состоит в том, что начиная с IE9 события OnLoad запускаются до загрузки всех изображений, и теперь трудно найти триггер для функции проверки.
Джин Винсент
11

Вы можете использовать событие load () - в jQuery, но оно не всегда срабатывает, если изображение загружается из кэша браузера. Этот плагин https://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js можно использовать для устранения этой проблемы.

jimmystormig
источник
8

Жизнь слишком коротка для 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
Это отличный ответ, но я не думаю, что вам даже нужно так много кода. Вы просто путаете это, добавляя srcJS.
Брэндон Бенефилд,
1
Время - огромное ограничение в программировании. Насколько я знаю, написание читаемого (хотя и долгого) кода дает огромную выгоду времени.
Идан Бекер
Зачем вам хранить src в новой переменной только для того, чтобы использовать ее в следующей строке? Если ваша цель - краткость, это анти-шаблон. myImage.src = https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620делает трюк.
Иосия
3

Вот эквивалент JQuery:

var $img = $('img');

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

function triggerAction() {
   alert('img has been loaded');
}
Александр Дробышевский
источник
1

Не подходит для 2008 года, когда был задан вопрос, но в эти дни это хорошо работает для меня:

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

Эти функции решат проблему, вам нужно реализовать DrawThumbnailsфункцию и иметь глобальную переменную для хранения изображений. Я люблю, чтобы это работало с объектом класса, у которого есть ThumbnailImageArrayпеременная-член, но я изо всех сил!

называется как в 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
Большая часть этого кода не имеет значения, включая всю вашу addThumbnailImagesфункцию. Сократите его до соответствующего кода, и я уберу -1.
Джастин Морган,
0

Если цель состоит в том, чтобы стилизовать img после того, как браузер отобразил изображение, вы должны:

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

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

потому что сначала браузер loads the compressed version of image, потом decodes itнаконец paintsто. поскольку для paintвас нет события, вы должны запустить свою логику после того, как в браузере есть decodedтег img.

Саяд
источник
-2

Если вы используете React.js, вы можете сделать это:

render() {

// ...

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

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

// ...}

Куда:

  • - onLoad (...) теперь будет вызываться с чем-то вроде этого: {src: " https: //......png ", ключ: "1"} вы можете использовать это как "ключ", чтобы знать, какие изображения загружен правильно, а который нет.
  • - onError (...) это то же самое, но для ошибок.
  • - объект "item" является чем-то вроде этого {key: "..", src: ".."}, который вы можете использовать для хранения URL-адреса изображений и ключа для использования в списке изображений.

  • Майк
    источник