jQuery зворотний виклик при завантаженні зображення (навіть коли зображення є кешованим)


291

Я хочу зробити:

$("img").bind('load', function() {
  // do stuff
});

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


12
З моменту вашого питання все змінилося. Зламаний плагін був переміщений до суті, а пізніше до репо з невеликим робочим плагіном jQuery.imagesLoaded . Вони фіксують усі маленькі химерності браузера .
Лоде

Вищезгадана бібліотека JQuery працювала для мене чудово. Дякую!
планг

Дякую за плагін, він працював чудово.
onimojo

Відповіді:


572

Якщо значення srcвже встановлено, подія запускається у кешованому випадку, перш ніж ви навіть зв’яжете обробник подій. Щоб виправити це, ви можете провести цикл, перевіривши та запустивши подію на основі .complete, наприклад:

$("img").one("load", function() {
  // do stuff
}).each(function() {
  if(this.complete) {
      $(this).load(); // For jQuery < 3.0 
      // $(this).trigger('load'); // For jQuery >= 3.0 
  }
});

Зверніть увагу на зміну з .bind()на, .one()щоб обробник подій не запускався двічі.


8
Ваше рішення спрацювало для мене ідеально, але я хочу щось зрозуміти, коли цей код "if (this.complete)" запуститься після завантаження вмісту зображення або раніше? тому що, як я можу зрозуміти. Це означає, що ви цикла на всіх $ ("img"), а вміст зображення порожній і завантаження не відбудеться. хммм, я думаю, у мене чогось не вистачає, буде добре, якщо ви можете описати, що відбувається, щоб зрозуміти це краще. Дякую.
Amr Elgarhy

33
З моменту вашої відповіді все змінилося. Зараз є невеликий робочий плагін jQuery.imagesLoaded . Вони фіксують усі маленькі химерності браузера .
Лоде

3
Я додав би setTimeout(function(){//do stuff},0)функцію "load" ... 0 дає системі браузера (DOM) ще один додатковий галочок, щоб забезпечити належне оновлення.
dsdsdsdsd

14
@Lode - це ВЕЛИЧИЙ плагін, зовсім не малий у будь-якому масштабі !!
vsync

5
оскільки метод JQuery 3 .load()не викликає події та має 1 необхідний аргумент, скористайтеся .trigger("load")натомість
ForceUser

48

Чи можу я запропонувати вам перезавантажити його в об'єкт зображення, що не DOM? Якщо він кешований, це взагалі не займе часу, і завантаження все одно буде спрацьовувати. Якщо він не кешований, він зніме завантаження під час завантаження зображення, що має бути в той самий час, коли версія DOM зображення закінчується завантаженням.

Javascript:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.src = $('#img').attr('src') ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;
}) ;

Оновлено (для обробки декількох зображень та з правильно впорядкованим вкладенням для завантаження):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;

1
Спробуйте приєднати loadобробник до його додавання, також це не працюватиме, але для одного зображення код OPs працює для багатьох :)
Нік Крейвер

Дякую, я додав оновлену версію, яка, сподіваюся, вирішує ці два питання.
Гас

#imgце ідентифікатор, не селектор елементів :) Також this.srcпрацює, немає необхідності використовувати jQuery там, де він не потрібен :) Але створення іншого зображення здається надмірним в будь-якому випадку ІМО.
Нік Крейвер

він повинен бути $ ('img'). але рішення - gr8 в 2k15 також
Дімаг Хараб

Також для випадку з декількома зображеннями, якщо ви хочете оперувати елементом DOM для кожного зображення в imageLoaded, тоді використовуйтеtmp.onload = imageLoaded.bind(this)
blisstdev

38

Моє просте рішення, йому не потрібен зовнішній плагін, і для загальних випадків повинно бути достатньо:

/**
 * Trigger a callback when the selected images are loaded:
 * @param {String} selector
 * @param {Function} callback
  */
var onImgLoad = function(selector, callback){
    $(selector).each(function(){
        if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
            callback.apply(this);
        }
        else {
            $(this).on('load', function(){
                callback.apply(this);
            });
        }
    });
};

використовуйте його так:

onImgLoad('img', function(){
    // do stuff
});

наприклад, для зникнення ваших зображень при завантаженні ви можете:

$('img').hide();
onImgLoad('img', function(){
    $(this).fadeIn(700);
});

Або як альтернатива, якщо ви віддаєте перевагу підходу, що нагадує плагін jquery:

/**
 * Trigger a callback when 'this' image is loaded:
 * @param {Function} callback
 */
(function($){
    $.fn.imgLoad = function(callback) {
        return this.each(function() {
            if (callback) {
                if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
                    callback.apply(this);
                }
                else {
                    $(this).on('load', function(){
                        callback.apply(this);
                    });
                }
            }
        });
    };
})(jQuery);

і використовувати його таким чином:

$('img').imgLoad(function(){
    // do stuff
});

наприклад:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});

urm .. а що робити, якщо у моїх зображень розмір встановлений css?
Simon_Weaver

Набір width, max-heightі відпустку height:auto, часто необхідно встановити як ширину і висоту , тільки якщо вам потрібно , щоб розтягнути зображення; Для більш надійного рішення я б використовував плагін на зразок ImagesLoaded
guari

1
так, це було заманливо, jsdoc все в порядку, я виправив приклад рядка
guari

1
Це рішення за допомогою $ .fn.imgLoad працює у веб-переглядачах. Виправити це буде ще краще: && / * для IE 10 - * / this.naturalHeight> 0 Цей рядок не братиме до уваги стиль css, оскільки img може бути заблокований, але має висоту. Робота в IE10
Патрик Падус

1
Це має (невелику) умову гонки. Зображення може завантажуватися в інший потік сценарію, і таким чином може завантажуватися між перевіркою завершення і приєднанням події завантаження, і в цьому випадку нічого не відбудеться. Зазвичай JS є синхронним з рендерінгом, тому вам не доведеться турбуватися про умови перегонів, але це виняток. html.spec.whatwg.org/multipage/…
Mog0

23

Вам справді доводиться робити це з jQuery? Ви також можете прикріпити onloadподію безпосередньо до свого зображення;

<img src="/path/to/image.jpg" onload="doStuff(this);" />

Він запускатиметься кожного разу, коли зображення завантажується, із кешу чи ні.


5
Це чистіше без вбудованого javascript
фундук

1
Привіт, Бьорн, чи onloadобробник запустить, коли зображення завантажується вдруге з кешу?
SexyBeast

1
@Cupidvogel ні, не буде.
Оголошення

3
Чувак, ти врятував мені життя, я спробував принаймні десяток інших рішень, і твоє єдине, що насправді спрацювало. Я серйозно замислююся над створенням ще 10 акаунтів, щоб проголосувати вашу відповідь ще 10 разів. Серйозно дякую!
Карло

1
Я ніколи не розумів відрази людей до наближення JS. Завантаження зображень відбувається окремо і поза послідовністю від решти процесу завантаження сторінки. Тому це єдине правильне рішення для отримання негайних відгуків про завершення завантаження зображення. Однак, якщо комусь потрібно чекати завантаження jQuery, і це станеться пізніше, тоді їм доведеться не використовувати просте рішення тут і використовувати одне з інших рішень (Piotr's, мабуть, найкращий варіант, оскільки він не залежить від псевдо- хаки, але перевірка висоти гуарі () теж може бути важливою). Черга на обробку також може бути корисною.
CubicleSoft

16

Ви також можете використовувати цей код з підтримкою помилки завантаження:

$("img").on('load', function() {
  // do stuff on success
})
.on('error', function() {
  // do stuff on smth wrong (error 404, etc.)
})
.each(function() {
    if(this.complete) {
      $(this).load();
    } else if(this.error) {
      $(this).error();
    }
});

1
Цей найкраще працював для мене. Я думаю, що ключовим є спочатку встановити loadобробник, а потім викликати його у eachфункції.
GreenRaccoon23

встановлення зображення за допомогою коду нижче '' var img = new Image (); img.src = sosImgURL; $ (img) .on ("load", function () {''
imdadhusen

13

У мене просто була ця проблема, я всюди шукав рішення, яке не передбачало вбивства мого кешу або завантаження плагіна.

Я не побачив цю тему одразу, тому знайшов щось інше, що цікаве виправлення та (я думаю) гідне розміщення тут:

$('.image').load(function(){
    // stuff
}).attr('src', 'new_src');

Я насправді отримав цю ідею з коментарів тут: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Я поняття не маю, чому це працює, але я протестував це на IE7 і де він зламався, перш ніж він працює.

Сподіваюся, це допоможе,

Редагувати

Прийнята відповідь фактично пояснює, чому:

Якщо src вже встановлений, подія запускається в кеш-пам’яті, перш ніж зв’язати обробник події.


4
Я перевірив, що це у багатьох браузерах, і я ніде не знайшов його збою. Я використовував $image.load(function(){ something(); }).attr('src', $image.attr('src'));для скидання початкового джерела.
Моріс

Я виявив, що такий підхід не працює на iOS, принаймні для Safari / 601.1 та Safari /
602.1

Було б дивовижно дізнатися чому, у якому браузері це?
Sammaye

5

Використовуючи jQuery для створення нового зображення за допомогою src зображення та присвоєння методу навантаження безпосередньо до цього, метод завантаження успішно викликається, коли jQuery закінчує генерування нового зображення. Це працює для мене в IE 8, 9 і 10

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});

Для тих, хто використовує Ruby on Rails, із віддаленим запитом, використовуючи шаблони __rjs.erb, це єдине знайдене нами рішення. Оскільки, використовуючи частки в js.erb, він втрачає зв'язування ($ ("# img" .on ("навантаження") ... а для зображень НЕ можна делегувати метод "on": $ ("body"). on ("load", "# img", function () ...
Альберт Катала

5

Я знайшов рішення https://bugs.chromium.org/p/chromium/isissue/detail?id=7731#c12 (Цей код взятий безпосередньо з коментаря)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;

Це саме те, що я шукав. Єдине зображення приходить до мене з сервера. Я хотів попередньо завантажити його, а потім подавати. Вибір усіх зображень, як і багато відповідей. Хороший.
Кай Цін

4

Модифікація прикладу GUS:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;

tmpImg.src = $('#img').attr('src');
})

Встановіть джерело до та після завантаження.


Як і у відповіді Гуса, це не працюватиме для декількох зображень ... і немає необхідності встановлювати srcперед прикріпленням onloadобробника, як тільки після цього буде достатньо.
Нік Крейвер

3

Просто знову додайте аргумент src в окремий рядок після того, як буде визначено oject oject. Це наштовхне IE на запуск події хлопця. Це некрасиво, але це найпростіший спосіб вирішення, який я знайшов поки що.

jQuery('<img/>', {
    src: url,
    id: 'whatever'
})
.load(function() {
})
.appendTo('#someelement');
$('#whatever').attr('src', url); // trigger .load on IE

1

Я можу дати вам невелику пораду, якщо ви хочете зробити так:

<div style="position:relative;width:100px;height:100px">
     <img src="loading.jpg" style='position:absolute;width:100px;height:100px;z-index:0'/>
     <img onLoad="$(this).fadeIn('normal').siblings('img').fadeOut('normal')" src="picture.jpg" style="display:none;position:absolute;width:100px;height:100px;z-index:1"/>
</div>

Якщо ви робите це, коли браузер кешує картинки, це не завжди проблема, яка відображається, але завантаження img під реальну картину.


1

У мене була ця проблема з IE, де e.target.width було б не визначено. Подія завантаження запуститься, але я не зміг отримати розміри зображення в IE (chrome + FF працював).

Виявляється, потрібно шукати e.currentTarget.naturalWidth & e.currentTarget.naturalHeight .

Ще раз IE робить речі власним (складнішим) способом.


0

Ви можете вирішити свою проблему за допомогою плагіна JAIL, який також дозволяє ледаче завантажувати зображення (покращуючи продуктивність сторінки) та передаючи зворотний виклик як параметр

$('img').asynchImageLoader({callback : function(){...}});

HTML повинен виглядати так

<img name="/global/images/sample1.jpg" src="/global/images/blank.gif" width="width" height="height" />

0

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

CSS:

.main_container{
    position: relative;
    width: 500px;
    height: 300px;
    background-color: #cccccc;
}

.center_horizontally{
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: green;
  left: 50%;
  top: 0;
  transform: translate(-50%,0);
}

.center_vertically{
  position: absolute;
  top: 50%;
  left: 0;
  width: 100px;
  height: 100px;
  background-color: blue;
  transform: translate(0,-50%);
}

.center{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  background-color: red;
  transform: translate(-50%,-50%);
}

HTML:

<div class="main_container">
  <div class="center_horizontally"></div>
  <div class="center_vertically"></div>
  <div class="center"></div>
  </div>
</div

Приклад Codepen

Приклад Codepen Менше


Чи можете ви навести приклад того, як це працює з завантаженням зображення?
Hastig Zusammenstellen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.