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


85

Я пишу 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));
  }

});

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

@ jon.wd7: я не знайомий з цим плагіном, і, можливо, він ще не був у далекому 2008 році. що стосується максимальної ширини та максимальної висоти, дві речі: 1) вони не підтримуються в IE (ну, я не впевнений у IE 8); 2) якщо розмір вікна перегляду змінюється (розмір вікна змінюється тощо), тоді мені все одно знадобиться javascript для зміни максимальної ширини / максимальної висоти (хоча я не можу, якщо використовував "100%", а не вимірювання пікселів)
Кіп

Це, безумовно, підтримується в IE7 та IE8, повідомляє quirksmode.org. Тож я не впевнений у вашій проблемі. Я особисто не підтримую IE6 за такі дрібниці, тому те, що вони побачать, - це те саме, що побачить користувач без увімкненого JS. І, звичайно, вам потрібно буде скинути max-widthі max-heightзмінити розмір. Але це досить легке завдання, .resize()адже насправді використовується однокласник.

3
Повний властивість дає імперативний спосіб дізнатися , чи був завантаженим чином.
Борис Окунський

1
@Adrien, Mozilla тепер показує завершеність, як це підтримується усіма основними браузерами, за винятком Andoid (невідомо).
Олівер Бок

Відповіді:


33

Або додайте слухач події, або попросіть зображення оголосити себе при завантаженні. Потім з’ясуйте розміри звідти.

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

Відповідно до специфікації, завантаження - це лише подія для основного елемента та елементів набору кадрів; сказано, я думаю, що це працює в IE, але я не знаю, що це працює в будь-яких інших браузерах або що це те, що ви можете припустити ... Я просто розглядав це кілька тижнів тому ...
Джейсон Вівсянка

Я тестував його в IE6, IE7, FF3, Opera9, Safair (Windows Beta) та Chrome (Windows Beta).
Кіп

9
Мережа поведінки та змісту не рекомендується. Події слід застосовувати за допомогою Javascript, а не в HTML.
dionyziz

10
Його коментар АКТУАЛЬНИЙ, оскільки ми не застрягли в 2008 році. Люди все ще читають це, і навіть якщо це не вважалося поганою практикою у 08, ви не хочете, щоб люди думали про його хорошу практику зараз.
Промовлено

3
document.querySelector ("img"). addEventListener ("load", function () {alert ('onload!');});
Франк Швітерман,

14

За допомогою сховища даних jquery ви можете визначити стан "завантаженого".

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

Тоді в іншому місці ви можете зробити:

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

2
Використовуйте jQuery(this)замість цього $(this)для кращої сумісності з іншими бібліотеками (jquery не володіє $), особливо коли у вас є JavaScript у html.
Джон Магнолія,

11

Правильною відповіддю є використання event.special.load

Можливо, подія завантаження не спрацює, якщо зображення завантажується з кешу браузера. Щоб врахувати таку можливість, ми можемо використовувати спеціальну подію завантаження, яка негайно спрацьовує, якщо зображення готове. event.special.load наразі доступний як плагін.

Відповідно до документів у .load ()


2
Я збирався додати відповідь із такою пропозицією, радий, що побачив цю відповідь перед кодуванням. В основному, ваші обробники повинні спочатку перевірити, чи завантажено зображення, перш ніж встановлювати обробник. Якщо він уже завантажений, негайно запустіть зворотний виклик. Це те, що $.readyробить. Я збирався запропонувати просто перевірити ширину, але це має свої проблеми, мені дуже подобається це рішення.
Хуан Мендес,

5

Ви хочете зробити те, що сказав Аллейн, однак пам’ятайте, що іноді зображення завантажується до готовності до дому, а це означає, що ваш обробник навантаження не спрацює. Найкращий спосіб зробити так, як говорить Аллаїн, але встановити src зображення за допомогою javascript після того, як приєднати завантажувач. Таким чином ви можете гарантувати, що він спрацює.

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


Сайт все ще працює для людей без Javascript, їм просто потрібно прокрутити, щоб побачити все зображення.
Кіп

4

Відповідно до одного з останніх коментарів до вашого оригінального запитання

$(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

2

Спробуйте щось на зразок:

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

6
Дякую. Однак існує ймовірність того, що зображення вже було завантажено до цього, і в цьому випадку подія завантаження не запускалася.
Кіп

Як щодо тегу сценарію, який встановлює цю подію відразу після тегу зображення? Причиною використання готового є переконатися, що завантажений весь документ, що в цьому випадку непотрібно, так?
Джейсон Гоемаат,

2

Існує плагін jQuery під назвою „imagesLoaded”, який забезпечує сумісний із браузером метод перевірки, чи завантажено зображення (елементи) елемента.

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

Використання для контейнера, у якому всередині багато зображень:

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

Плагін чудовий:

  1. працює для перевірки контейнера з великою кількістю зображень всередині
  2. працює для перевірки img, щоб перевірити, чи завантажився він

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

1

Будь-які коментарі щодо цього?

...

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

1

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

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

цікава ідея. отже, знаючи, коли зображення робиться легко. Але що, якби зображення не вдалося завантажити. Я шукав спосіб дізнатися, чи не вдалося завантажити зображення. і ти дав мені уявлення про час очікування, щоб завантажити його. +1 за це
дуб

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

зауважте, що для jquery, щоб підняти .error, дві речі повинні мати 1. дескриптор, але встановлюватися до виникнення помилки. 2. .error обробляє лише протокол http, а не файл: //, тому ви не отримаєте там помилки ..
oak

у моєму прикладі коду обробник успіху / помилки встановлюється перед призначенням атрибута src саме з цієї причини. про file://обмеження - мені ніколи не потрібно було пов'язувати зображення за допомогою файлового протоколу, і я не думаю, що є велика потреба.
roberkules

1

Ця функція перевіряє, чи завантажується зображення на основі вимірюваних розмірів. Цей прийом корисний, якщо ваш сценарій виконується після завантаження деяких зображень.

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

1

Я виявив, що це спрацювало на мене

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

Загалом кредит належить Франку Швітерману, який прокоментував прийняту відповідь. Мені довелося помістити це сюди, це надто цінно ...


0

Ми розробили сторінку, де вона завантажувала декілька зображень, а потім виконувала інші функції лише після завантаження зображення. Це був зайнятий сайт, який генерував багато трафіку. Здається, що такий простий скрипт працював практично у всіх браузерах:

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

Але це потенційне питання для IE9!

ЄДИНИЙ браузер, про який ми повідомляли про проблеми, це IE9. Хіба ми не здивовані? Здається, що найкращий спосіб вирішити проблему - це не призначати зображенню src до тих пір, поки ПІСЛЯ не буде визначена функція завантаження, наприклад:

$(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обробника навіть не було проблемою.


0

Чи можу я запропонувати чисте рішення 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>


0

Я вважаю, що це просте рішення найкраще для мене працює:

        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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.