Как определить, загружено ли изображение, используя Javascript/jQuery?

Я пишу Javascript, чтобы изменить размер большого изображения, чтобы оно входило в окно браузера. (К сожалению, я не контролирую размер исходных изображений.)

Итак, что-то вроде этого будет в HTML:

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

Есть ли способ определить, загружено ли изображение src в теге img?

Мне нужно это, потому что я столкнулся с проблемой, если $(document).ready() выполняется до того, как браузер загрузил изображение. $("#photo").width() и $("#photo").height() вернут размер заполнителя (текст alt). В моем случае это что-то вроде 134 x 20.

Сейчас я просто проверяю, меньше ли высота фото 150, и предполагая, что если это просто текст. Но это довольно взломать, и это сломается, если фотография будет меньше 150 пикселей (вряд ли в моем конкретном случае), или если текст alt превышает 150 пикселей (возможно, это произойдет в маленьком окне браузера).


Изменить: Для тех, кто хочет увидеть код:

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

});

Обновить. Спасибо за предложения. Существует риск того, что событие не будет запущено, если я установил обратный вызов для события $("#photo").load, поэтому я определил событие onLoad непосредственно на теге изображения. Для записи здесь приведен код, в который я попал:

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

Затем в 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

Либо добавьте прослушиватель событий, либо покажите объявление с загрузкой. Затем определите размеры оттуда.

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

Ответ 2

Используя хранилище данных jquery, вы можете определить "загруженное" состояние.

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

В другом месте вы можете:

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

Ответ 3

Правильный ответ: использовать event.special.load

Возможно, событие загрузки не будет запущено, если изображение загрузится из кеша браузера. Чтобы учесть эту возможность, мы можем использовать специальное событие загрузки, которое срабатывает немедленно, если изображение будет готово. event.special.load в настоящее время доступен как плагин.

В документах . load()

Ответ 4

Вы хотите сделать то, что сказал Аллайн, однако имейте в виду, что иногда изображение загружается до готовности дома, что означает, что ваш обработчик нагрузки не срабатывает. Лучший способ - сделать так, как говорит Аллайн, но установить src изображения с помощью javascript после прикрепления загрузчика. Таким образом вы можете гарантировать, что он срабатывает.

Что касается доступности, будет ли ваш сайт работать для людей без javascript? Возможно, вы захотите присвоить img-тегу правильный src, приложите к нему готовый обработчик dom, чтобы запустить js: очистите изображение src (дайте ему фиксированный и высоту с помощью css, чтобы предотвратить мерцание страницы), а затем установите обработчик нагрузки img, затем reset src в правильный файл. Таким образом, вы охватываете все базы:)

Ответ 5

Согласно одному из последних комментариев к вашему оригинальному вопросу

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

Предупреждение. Этот ответ может вызвать серьезный цикл в ie8 и ниже, потому что img.complete не всегда правильно установлен браузером. Если вы должны поддерживать ie8, используйте флаг для запоминания загрузки изображения.

Ответ 6

Попробуйте что-то вроде:

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

Ответ 7

Любые комментарии к этому?

...

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

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

doShow();

...

Похоже на работу везде...

Ответ 8

Здесь есть плагин jQuery под названием "imagesLoaded", который обеспечивает совместимый с кросс-браузером способ проверки загрузки изображений элементов.

Сайт: https://github.com/desandro/imagesloaded/

Использование контейнера с большим количеством изображений внутри:

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

Плагин отличный:

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

Ответ 9

Я нашел, что это сработало для меня

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

Кредит идет полностью к Фрэнку Швиерману, который прокомментировал принятый ответ. Я должен был поставить это здесь, это слишком ценно...

Ответ 10

Я только что создал функцию jQuery для загрузки изображения с помощью jQuerys Deferred Object, который позволяет очень легко реагировать на событие load/error:

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

Применение:

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

Посмотрите, как работает: http://jsfiddle.net/roberkules/AdWZj/

Ответ 11

Эта функция проверяет, загружено ли изображение на основе измеримых измерений. Этот метод полезен, если ваш script выполняется после того, как некоторые из изображений уже загружены.

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

Ответ 12

Мы разработали страницу, где загрузили несколько изображений, а затем выполнили другие функции только после загрузки изображения. Это был загруженный сайт, который генерировал много трафика. Похоже, что следующий простой script работал практически со всеми браузерами:

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

, НО ЭТО ПОТЕНЦИАЛЬНЫЙ ВОПРОС ДЛЯ IE9!

Единственный браузер, о котором мы сообщали, это IE9. Разве мы не удивлены? Кажется, что лучший способ решить проблему - не назначать src для изображения до тех пор, пока не будет определена функция onload, например:

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

Кажется, что IE 9 иногда не бросает событие onload по любой причине. Другие решения на этой странице (например, от Эвана Кэрролла, например) все еще не работают. Логически, что проверено, было ли состояние загрузки уже успешным и вызвало функцию, а если нет, то установите обработчик onload, но даже когда вы это сделаете, мы продемонстрировали, что изображение может загружаться между этими двумя строками js, тем самым не загружается в первую строку, а затем загружается до того, как установлен обработчик onload.

Мы обнаружили, что лучший способ получить то, что вы хотите, - не определять изображение src, пока вы не установили триггер события onload.

Мы только недавно перестали поддерживать IE8, поэтому я не могу говорить о версиях до IE9, в противном случае из всех других браузеров, которые были использованы на сайте - IE10 и 11, а также Firefox, Chrome, Opera, Safari и любые пользователи мобильных браузеров - установка src перед назначением обработчика onload не была даже проблемой.

Ответ 13

Могу ли я предложить чистое решение CSS в целом?

Просто используйте Div, в котором вы хотите показать изображение. Установите изображение в качестве фона. Затем укажите свойство background-size: cover или background-size: contain зависимости от того, как вы этого хотите.

cover: обрезает изображение до тех пор, пока меньшие стороны не покроют коробку. contain: будет держать все изображение внутри div, оставляя вас с пробелами по бокам.

Проверьте фрагмент ниже.

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>