Как с помощью 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() вернут размер заполнителя (альтернативный текст). В моем случае это что-то вроде 134 x 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));
  }

});

Это так давно, и вы уже приняли ответ, поэтому я просто прокомментирую здесь. Почему вы не можете использовать плагин jQuery onImagesLoad? А также, jQuery или нет, что не так с настройкой max-width и max-height в стиле изображения с помощью Javascript? Затем вы избегаете ВСЕГО кода, который вам нужно написать, устанавливая максимальную ширину / высоту равной размеру ширины / высоты области просмотра.

user136565 23.01.2010 00:13

@ jon.wd7: я не знаком с этим плагином, и, возможно, его не было еще в '08. что касается max-width и max-height, две вещи: 1) они не поддерживаются в IE (ну, насчет IE 8 я не уверен); 2) если окно просмотра меняет размер (размер окна изменяется и т. д.), Мне все равно понадобится javascript, чтобы изменить максимальную ширину / максимальную высоту (хотя я не могу, если бы я использовал «100%», а не измерение в пикселях)

Kip 23.01.2010 00:27

Согласно quirksmode.org, он определенно поддерживается в IE7 и IE8. Так что я не уверен в вашей проблеме. Я лично не поддерживаю IE6 для подобных мелочей, поэтому они увидят то же самое, что увидит пользователь без включенного JS. И, конечно же, вам нужно будет сбросить max-width и max-height при изменении размера. Но это довольно простая задача, фактически однострочная с использованием .resize().

user136565 23.01.2010 00:31

Свойство полный дает обязательный способ узнать, загружено ли изображение.

BorisOkunskiy 23.09.2013 21:56

@incarnate Я не согласен. Поскольку свойство complete элемента изображения явно не поддерживается: невозможно найти надежный источник информации о поддержке браузером. Это единственное упоминание об этом в спецификации HTML5, и на момент написания она все еще находится в черновой версии. см. единственную спецификацию, касающуюся "полного" свойства w3.org/html/wg/drafts/html/master/…, а Mozilla показывает поддержку свойства "complete" как неизвестное developer.mozilla.org/en/docs/Web/API/HTMLImageElement

Adrien Be 14.11.2014 18:36

Библиотека javascript imagesloaded отлично справляется с этой задачей. См. stackoverflow.com/questions/1977871/…

Adrien Be 14.11.2014 18:38

@Adrien, Mozilla теперь показывает завершена, поскольку поддерживается всеми основными браузерами, кроме Andoid (неизвестно).

Oliver Bock 09.12.2015 01:43
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
84
7
128 286
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Ответ принят как подходящий

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

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

Согласно спецификации, onload - это только событие для элементов body и frameset; Тем не менее, я думаю, что это работает в IE, но я не знаю, работает ли это в каких-либо других браузерах или что вы можете предположить, что это то, что вы можете предположить ... Я только что изучал это пару недель назад ...

Jason Bunting 05.11.2008 09:06

Я тестировал его в IE6, IE7, FF3, Opera9, Safair (Windows Beta) и Chrome (Windows Beta).

Kip 05.11.2008 17:48

Беспорядочное поведение и контент не приветствуются. События следует применять с использованием Javascript, а не HTML.

dionyziz 14.12.2012 12:25

Его комментарий актуален, поскольку мы не застряли в 2008 году. Люди все еще читают это, и даже если это не считалось плохой практикой в ​​08, вы не хотите, чтобы люди думали, что это хорошая практика сейчас.

Spoeken 05.03.2013 16:28

Итак, какое сейчас лучшее решение или передовой опыт в 2013 году .... @MathiasMadsenStav

Hitesh 30.08.2013 16:37

Я думаю, что кто-то должен дать лучший ответ на этот вопрос, который поможет другим, я знаю, что на этот вопрос уже есть правильный ответ, но я надеюсь, что они могут быть лучше ответом без беспорядочного поведения и содержимого с использованием java script или jquery :):) ... просто мысль ..... @ dionyziz

Hitesh 30.08.2013 16:40

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

Frank Schwieterman 28.11.2013 02:19

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

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

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

Kip 05.11.2008 17:47

Как насчет тега сценария, устанавливающего это событие сразу после тега изображения? Причина использования ready - убедиться, что загружен весь документ, что в данном случае не нужно, верно?

Jason Goemaat 29.09.2010 02:02

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

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

Сайт по-прежнему работает для людей без Javascript, им просто нужно прокрутить, чтобы увидеть все изображение.

Kip 05.11.2008 17:49

Есть комментарии по этому поводу?

...

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

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

doShow();

...

Вроде везде работает ...

использование setTimeout - плохая практика

cdalxndr 24.04.2020 11:05

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

It is possible that the load event will not be triggered if the image is loaded from the browser cache. To account for this possibility, we can use a special load event that fires immediately if the image is ready. event.special.load is currently available as a plugin.

Согласно документам на .нагрузка()

Я собирался добавить ответ с таким предложением, рад, что увидел этот ответ, прежде чем его кодировать. По сути, ваши обработчики должны сначала проверить, загружено ли изображение, прежде чем устанавливать обработчик. Если он уже загружен, немедленно активируйте обратный вызов. Это то, что делает $.ready. Я собирался предложить просто проверить ширину, но в этом есть свои проблемы, мне очень нравится это решение.

Juan Mendes 12.03.2013 23:11

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

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

Тогда в другом месте вы можете сделать:

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

Используйте jQuery(this) вместо $(this) для лучшей совместимости с другими библиотеками (jquery не владеет $), особенно если у вас есть JavaScript в html.

John Magnolia 16.05.2013 17:30

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

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

Звучит замечательно. Не могли бы вы привести точный пример того, когда ваш код предпочтительнее img.onload и img.onerror? Ваш код предназначен только для обработки кажущихся недостатков обработки ошибок jQuery, о которых я только что был проинформирован: эта ошибка не запускается в IE, если нет расширения файла?

mplungjan 12.06.2012 09:44

интересная идея. так что зная, когда изображение стало проще. Но что, если изображение не может быть загружено. Я искал способ узнать, не удалось ли загрузить изображение. и вы дали мне идею тайм-аута при его загрузке. +1 за это

oak 07.02.2014 12:15

@oak тайм-аут должен быть только запасным вариантом. большинство браузеров должны запускать событие error, которое обрабатывается .error(function(e) { defer.rejectWith($img); }). Если вы посмотрите на jsFiddle, вы увидите, что текст http://www.google.com/abc.png not found отображается сразу в панели результатов (не дожидаясь тайм-аута, потому что произошло событие ошибки)

roberkules 07.02.2014 19:38

обратите внимание, что для того, чтобы jquery поднял .error, должны быть две вещи: 1. дескриптор, но они должны быть установлены до возникновения ошибки. 2. .error обрабатывает только протокол http, а не file: //, поэтому вы не получите там ошибки ..

oak 10.02.2014 18:10

в моем примере кода обработчик успеха / ошибки устанавливается перед назначением атрибута src именно по этой причине. насчет ограничения file:// - мне никогда не нужно было связывать изображения с использованием файлового протокола, и я не думаю, что в этом особая необходимость.

roberkules 10.02.2014 19:03

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

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

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

Ralph Ritoch 10.08.2013 13:42

Существует плагин jQuery под названием «imagesLoaded», который предоставляет кроссбраузерный метод проверки, загружены ли изображения элемента.

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

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

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

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

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

кажется довольно тяжелым 5 КБ, уменьшенным только для проверки загруженного img. Должен быть доступный более простой способ зажигалки ...

cdalxndr 24.04.2020 11:08

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

$(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, используйте флаг, чтобы запомнить, что изображение загружено.

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

commonpike 28.07.2014 15:30

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

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

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

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

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

НО ЭТО ПОТЕНЦИАЛЬНАЯ ПРОБЛЕМА ДЛЯ IE9!

ЕДИНСТВЕННЫЙ браузер, о котором мы сообщали о проблемах, - это IE9. Мы не удивлены? Кажется, что лучший способ решить проблему - не назначать src изображению до тех пор, пока ПОСЛЕ определения функции onload, например:

$(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 даже не была проблемой.

Могу я вообще предложить решение на чистом 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>

Я считаю, что мне лучше всего подходит это простое решение:

        function setEqualHeight(a, b) {
            if (!$(a).height()) {
                return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
            }
            $(b).height($(a).height());
        }

        $(document).ready(function() {
            setEqualHeight('#image', '#description');
            $(window).resize(function(){setEqualHeight('#image', '#description')});
        });
    </script>

Другие вопросы по теме