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

Я пишу некоторый 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() вернут размер заполнителя (альтернативный текст). В моем случае это что-то вроде 134 х 20.

Прямо сейчас я просто проверяю, меньше ли высота фотографии, чем 150, и предполагаю, что если это так, то это просто альтернативный текст. Но это довольно взломано, и оно сломается, если фотография будет иметь высоту менее 150 пикселей (в моем конкретном случае это маловероятно), или если высота альтернативного текста превышает 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));
  }

});

Ответы [ 13 ]

1 голос
/ 17 февраля 2012

Я только что создал функцию 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'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");
        });
    }
});

Использование:

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/

0 голосов
/ 29 мая 2019

Могу ли я вообще предложить чистое решение 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 style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)" class="cover-image">
</div>
<br/>
<div style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)" class="contain-image">
</div>
0 голосов
/ 03 декабря 2014

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

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

НО ЭТО ПОТЕНЦИАЛЬНЫЙ ВЫПУСК IE9!

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...