Попередня завантаження зображень за допомогою jQuery


689

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

Я це бачив тут ( http: //nettuts.com ... ):

function complexLoad(config, fileNames) {
  for (var x = 0; x < fileNames.length; x++) {
    $("<img>").attr({
      id: fileNames[x],
      src: config.imgDir + fileNames[x] + config.imgFormat,
      title: "The " + fileNames[x] + " nebula"
    }).appendTo("#" + config.imgContainer).css({ display: "none" });
  }
};

Але це виглядає дещо перевершеним для того, що я хочу!

Я знаю, що там є плагіни jQuery, які роблять це, але всі вони здаються трохи великими (за розміром); Мені просто потрібен швидкий, простий і короткий спосіб попередньої завантаження зображень!


10
$.each(arguments,function(){(new Image).src=this});
Девід Гелсінг

Відповіді:


969

Швидко та просто:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(){
        $('<img/>')[0].src = this;
        // Alternatively you could use:
        // (new Image()).src = this;
    });
}

// Usage:

preload([
    'img/imageName.jpg',
    'img/anotherOne.jpg',
    'img/blahblahblah.jpg'
]);

Або якщо ви хочете плагін jQuery:

$.fn.preload = function() {
    this.each(function(){
        $('<img/>')[0].src = this;
    });
}

// Usage:

$(['img1.jpg','img2.jpg','img3.jpg']).preload();

25
Чи не потрібно елемент зображення вставляти в DOM, щоб браузер кешував його?
JoshNaro

8
Я вважаю, що $('<img />')просто створюється елемент зображення в пам'яті (див. Посилання ). Схоже '$('<img src="' + this + '" />'), насправді створили б елемент у прихованому DIV, оскільки він "складніший". Однак я не думаю, що це потрібно для більшості браузерів.
JoshNaro

104
Це дивний спосіб написання плагіна jQuery. Чому ні $.preload(['img1.jpg', 'img2.jpg'])?
alex

12
Не забудьте зателефонувати цьому всередину, $(window).load(function(){/*preload here*/});оскільки таким чином усі зображення в документі завантажуються спочатку, швидше за все, вони спочатку потрібні.
Джаспер Кенніс

12
@RegionalC - Може бути трохи безпечніше встановити loadподію перед встановленням на srcвипадок, якщо зображення закінчується завантаженням до встановлення події завантаження? $('<img/>').load(function() { /* it's loaded! */ }).attr('src', this);
запчастини

102

Ось виправлена ​​версія першої відповіді, яка фактично завантажує зображення в DOM і приховує їх за замовчуванням.

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}

38
hide()є більш лаконічним, ніж css('display', 'none').
алекс

6
Яка перевага вставки їх у DOM?
alex

Я також хотів би знати перевагу вставки їх у DOM.
jedmao

11
З мого досвіду, попередньо завантажуючи зображення в DOM, браузер усвідомлює його існування та правильне кешування. В іншому випадку зображення існує лише в пам'яті, яка працює лише для програм на одній сторінці.
Денніс Ронго

Денніс Ронго. Додавання зображень до DOM фіксується випадковим повторним завантаженням у Chrome. Дякую!
tmorell

52

Використовуйте об’єкт зображення JavaScript .

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

var preloadPictures = function(pictureUrls, callback) {
    var i,
        j,
        loaded = 0;

    for (i = 0, j = pictureUrls.length; i < j; i++) {
        (function (img, src) {
            img.onload = function () {                               
                if (++loaded == pictureUrls.length && callback) {
                    callback();
                }
            };

            // Use the following callback methods to debug
            // in case of an unexpected behavior.
            img.onerror = function () {};
            img.onabort = function () {};

            img.src = src;
        } (new Image(), pictureUrls[i]));
    }
};

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('a');
});

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('b');
});

4
Зробіть правильно, використовуйте об’єкт JavaScript Image. Ви спостерігали, як люди робили неправильно в цих відповідях?
alex

Блискучий код. Чи правильно я вважаю, що це призведе до запуску onloadподії, навіть якщо зображення буде кешоване? (Тому що img.onloadоголошено першим). Це показали мої тести.
Startec

3
@ Алекс потенційно, так. Якщо мета полягає в попередньому завантаженні (що передбачає порядок виконання), то я вважаю за краще бачити необроблений варіант JS замість залежних від jQuery параметрів.
Charlie Schliesser

Мені сподобалося це рішення, але я просто виявив, що воно не працює в моєму Firefox. Це лише я або інші проблеми з тим же?
Газiльйон

@Gazillion дайте більше деталей. Як ви визначаєте "не працює"? Що таке версія FF?
Гаджус

35

JP, Після перевірки вашого рішення у мене все ще виникали проблеми у Firefox, де він не попередньо завантажував зображення перед тим, як рухатись разом із завантаженням сторінки. Я виявив це, помістивши деякі sleep(5)в сценарій мого сервера. Я реалізував таке рішення на основі вашого, яке, здається, вирішує це.

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

// Helper function, used below.
// Usage: ['img1.jpg','img2.jpg'].remove('img1.jpg');
Array.prototype.remove = function(element) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == element) { this.splice(i,1); }
  }
};

// Usage: $(['img1.jpg','img2.jpg']).preloadImages(function(){ ... });
// Callback function gets called after all images are preloaded
$.fn.preloadImages = function(callback) {
  checklist = this.toArray();
  this.each(function() {
    $('<img>').attr({ src: this }).load(function() {
      checklist.remove($(this).attr('src'));
      if (checklist.length == 0) { callback(); }
    });
  });
};

У моєму контексті я з інтересу використовую наступне:

$.post('/submit_stuff', { id: 123 }, function(response) {
  $([response.imgsrc1, response.imgsrc2]).preloadImages(function(){
    // Update page with response data
  });
});

Сподіваємось, це допомагає тому, хто заходить на цю сторінку з Google (як я), шукаючи рішення для попередньої завантаження зображень на дзвінки Ajax.


2
Для тих, хто не зацікавлений у зіпсуванні Array.prototype, натомість ви можете зробити: checklist = this.lengthА в функції завантаження: checklist--Тоді:if (checklist == 0) callback();
MiniGod

3
Все було б добре, однак додавання нових або видалення існуючих методів до об’єкта, яким ви не володієте, є однією з найгірших практик роботи в JavaScript.
Ріхардс

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

.attr({ src: this }).load(function() {...})в .load(function() {...}).attr({ src: this })іншому випадку у вас будуть проблеми з кешуванням.
Кевін Б

25

Цей однорядковий код jQuery створює (і завантажує) img елемент DOM, не показуючи його:

$('<img src="img/1.jpg"/>');

4
@huzzah - Можливо, вам буде краще просто використовувати спрайти. Менше http-запитів. :)
Алекс К

22
$.fn.preload = function (callback) {
  var length = this.length;
  var iterator = 0;

  return this.each(function () {
    var self = this;
    var tmp = new Image();

    if (callback) tmp.onload = function () {
      callback.call(self, 100 * ++iterator / length, iterator === length);
    };

    tmp.src = this.src;
  });
};

Використання досить просте:

$('img').preload(function(perc, done) {
  console.log(this, perc, done);
});

http://jsfiddle.net/yckart/ACbTK/


Це дійсно гарна відповідь, це справді має бути найкращим відповіді imho.
сонник

1
Деякі пояснювальні слова було б добре.
robsch

Хороша відповідь, але я пропоную використовувати picsum.photos замість lorempixel.com
Олександр

19

У мене є невеликий плагін, який справляється з цим.

Це називається waitForImages, і він може обробляти imgелементи або будь-який елемент із посиланням на зображення в CSS, наприклад div { background: url(img.png) }.

Якщо ви просто хотіли завантажити всі зображення, включаючи ті, на які посилається у CSS, ось як би це зробити :)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});

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

@DaveCameron Не враховує, бачать чи ні зображення Ви можете легко розщедрити його та внести ці зміни - просто додайте :visibleдо спеціального селектора.
alex

Цей плагін виглядає дуже цікаво. Однак документація jquery підкреслює, що loadподія, застосована до зображень: "не працює послідовно, ані надійно переглядає браузер". Як плагіну вдалося обійти це?
EleventyOne

@EleventyOne Перевірте джерело щодо користувацького селектора.
alex

@alex Як цей плагін завантажує зображення, встановлені в css на: наведення елемента на елемент? Для мене це не працює
Філіп Хофманн

13

ви можете завантажувати зображення у свій HTML де-небудь за допомогою display:none;правила css , а потім показувати їх, коли потрібно за допомогою js або jquery

не використовуйте функції js або jquery для попереднього завантаження - це лише правило css Vs для багатьох рядків js, які потрібно виконати

приклад: Html

<img src="someimg.png" class="hide" alt=""/>

Css:

.hide{
display:none;
}

jQuery:

//if want to show img 
$('.hide').show();
//if want to hide
$('.hide').hide();

Попередня завантаження зображень jquery / javascript не є гарною, тому що завантажувати зображення потрібно кілька мілісекунд на сторінку + у вас є мілісекунди для розбору та виконання сценарію, особливо тоді, якщо вони є великими зображеннями, тому приховування їх у hml краще також для продуктивності, тому що зображення дійсно попередньо завантажене, без того, щоб це було видно, поки ви не покажете це!


2
Більш детальну інформацію про цей підхід можна знайти тут: perishablepress.com / ...
gdelfino

3
Але потрібно пам’ятати, що ця методика має головний недолік: ваша сторінка не буде повністю завантажена, поки всі зображення не завантажуються. Залежно від кількості зображень для попереднього завантаження та їх розміру, це може зайняти деякий час. Ще гірше, якщо тег <img> не визначає висоту та ширину, деякі веб-переглядачі можуть зачекати, поки зображення буде отримане, перш ніж надавати решту сторінки.

@Alex вам так чи інакше потрібно завантажити IMG, ви можете вибирати, чи завантажувати їх у форматі html та уникати будь-яких мерехтливих та напівзавантажених зображень, або якщо ви хочете отримати більше швидкості для нестабільного рішення
itsme

також я дійсно думаю, що створювати HTML-теги за допомогою JavaScript не можна прочитати взагалі лише моїх 2 копійки
itsme

1
Мені потрібно було дуже швидке рішення для дуже складного проекту, і це було все.
Гроза

13

цей плагін jquery imageLoader становить всього 1,39 кб

використання:

$({}).imageLoader({
    images: [src1,src2,src3...],
    allcomplete:function(e,ui){
        //images are ready here
        //your code - site.fadeIn() or something like that
    }
});

Є також інші варіанти, наприклад, бажаєте завантажувати зображення синхронно або асихронно, і завершення події для кожного окремого зображення.


@AamirAfridi Чому це?
Ян

1
@Ian, оскільки документ вже готовий до моменту запуску зворотного дзвінка. $ (документ). вже використовується, щоб переконатися, що ваш DOM завантажений. Що стосується зворотного дзвінка, це означає, що всі зображення завантажені, це означає, що yoru DOM завантажений, тому немає необхідності в документі. Вже всередині зворотного дзвінка.
Аамір Африді

1
@AamirAfridi Немає гарантії, що документ готовий у зворотному дзвінку ... звідки ви це зробите? На сторінці плагіна немає нічого, що говорить про те, що allcompleteзворотний виклик виконується після того, як DOM буде готовий. Існує досить хороший шанс, що зображення закінчуються завантаженням після того, як DOM буде готовий, але причин припускати це немає. Я не знаю, чому ви вважаєте, що зворотні виклики є магічними та виконуються після того, як DOM буде готовий ... чи можете ви пояснити, звідки ви це отримуєте? Просто тому , що завантажуються зображення не означає , що DOM готова
Ian

@AamirAfridi А в документації на плагін навіть сказано: NB to use this as an image preloader simply put your $(document).ready(function(){}); into your 'allcomplete' event : > simples!... він безпосередньо рекомендує, що показує ця відповідь.
Ян

5
@AamirAfridi Це не має сенсу для цієї ситуації. Плагін є попереднім завантажувачем. Ви хочете виконати його якнайшвидше. І є багато речей, які не залежать від DOM, який ви хочете звільнити якомога швидше, і тоді, коли DOM буде готовий, зробіть щось.
Ян

9

Швидкий спосіб завантаження зображень у jQuery та отримання функції зворотного виклику без плагінів - це створення декількох imgтегів одночасно та підрахунок відповідей, наприклад

function preload(files, cb) {
    var len = files.length;
    $(files.map(function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}

preload(["one.jpg", "two.png", "three.png"], function() {
    /* Code here is called once all files are loaded. */
});
    

Зауважте, що якщо ви хочете підтримати IE7, вам потрібно буде використовувати цю трохи менш гарну версію (яка також працює в інших браузерах):

function preload(files, cb) {
    var len = files.length;
    $($.map(files, function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}

7

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

$("img").each(function(){
    var imgsrc = $(this).attr('src');
    if(imgsrc.match('_th.jpg') || imgsrc.match('_home.jpg')){
      imgsrc = thumbToLarge(imgsrc);
      (new Image()).src = imgsrc;   
    }
});

В основному, для кожного зображення на сторінці він захоплює src кожного зображення, якщо він відповідає певним критеріям (це великий палець або зображення домашньої сторінки), він змінює ім'я (основний рядок замінить на зображенні src), а потім завантажує зображення .

У моєму випадку на сторінці було повно зображень великого пальця, всі назвали щось на зразок image_th.jpg, а всі відповідні великі зображення названі image_lg.jpg. Великий палець великого просто замінює _th.jpg на _lg.jpg, а потім попередньо завантажує всі великі зображення.

Сподіваюся, що це комусь допоможе.


3
    jQuery.preloadImage=function(src,onSuccess,onError)
    {
        var img = new Image()
        img.src=src;
        var error=false;
        img.onerror=function(){
            error=true;
            if(onError)onError.call(img);
        }
        if(error==false)    
        setTimeout(function(){
            if(img.height>0&&img.width>0){ 
                if(onSuccess)onSuccess.call(img);
                return img;
            }   else {
                setTimeout(arguments.callee,5);
            }   
        },0);
        return img; 
    }

    jQuery.preloadImages=function(arrayOfImages){
        jQuery.each(arrayOfImages,function(){
            jQuery.preloadImage(this);
        })
    }
 // example   
    jQuery.preloadImage(
        'img/someimage.jpg',
        function(){
            /*complete
            this.width!=0 == true
            */
        },
        function(){
            /*error*/
        }
    )

7
Ласкаво просимо до переповнення стека! Замість того, щоб опублікувати лише блок коду, поясніть, чому цей код вирішує поставлену проблему. Без пояснення це не відповідь.
Martijn Pieters

3

Я використовую такий код:

$("#myImage").attr("src","img/spinner.gif");

var img = new Image();
$(img).load(function() {
    $("#myImage").attr("src",img.src);
});
img.src = "http://example.com/imageToPreload.jpg";

Спочатку прив’яжіть до події завантаження, а потім встановіть src.
Кевін Б

1

Я використовую файл Manifest, щоб повідомити (сучасні) веб-браузери, щоб також завантажувати всі відповідні зображення та кешувати їх. Використовуйте Grunt і grunt-manifest, щоб зробити це автоматично і ніколи більше не переживайте за сценарії попереднього завантаження, інваліди кешу, CDN тощо.

https://github.com/gunta/grunt-manifest


0

Це працює для мене навіть у IE9:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });

1
Зрештою, це не вдасться через кешування, завжди пов'язуйте подію навантаження перед встановленням атрибута src.
Кевін Б

0

Я хотів це зробити за допомогою спеціального накладання API Google Maps. Їх зразок коду просто використовує JS для вставки елементів IMG, і поле заповнення зображення відображається до завантаження зображення. Тут я знайшов відповідь, яка працювала на мене: https://stackoverflow.com/a/10863680/2095698 .

$('<img src="'+ imgPaht +'">').load(function() {
$(this).width(some).height(some).appendTo('#some_target');
});

Це попередньо завантажує зображення, як було запропоновано раніше, а потім використовує обробник, щоб додати об’єкт img після завантаження URL-адреси img. Документація jQuery попереджає, що кешовані зображення не працюють добре з цим кодом подій / обробника, але він працює для мене у FireFox та Chrome, і мені не потрібно турбуватися про IE.


Це не буде добре працювати з кешованими зображеннями, як ви з'ясували. вирішення полягає в тому, щоб спочатку зв’язати подію навантаження, а потім встановити атрибут src.
Кевін Б

-1
function preload(imgs) {
    $(imgs).each(function(index, value) {
        $('<img />').attr('src', value).appendTo('body').css('display', 'none');
    });
}

.attr('src',value) ні .attr('src',this)

просто вказати на це :)


Обсяг thisвсередині зворотного дзвінка, який передається $.each, присвоюється значенню, яке повторюється.
Ойбек

? $ (['img1.jpg', 'img2.jpg', 'img3.jpg']). кожен (функція (індекс, значення) {console.log (значення); // img1.jpg console.log (це) ; // Рядок {0 = "i", 1 = "m", 2 = "g", більше ...} $ ('<img />'). Attr ('src', це) .appendTo (' body '). css (' показ ',' немає ');});
Вішер

Гм. Я здогадуюсь, ти тут. Наприклад, $("div").each(function(i, el){ console.log(el == this);});генерує всі trues; Ітерація над масивом, схоже, поводиться по-різному.
Ойбек

-2

5 рядків у кофескрипті

array = ['/img/movie1.png','/img/movie2.png','/img/movie3.png']

$(document).ready ->
  for index, image of array
    img[index] = new Image()
    img[index].src = image

2
Чи можете ви розширити, як працює рішення для вирішення питання в ОП? І, можливо, прокоментуйте ваш код, щоб інші могли легше його зрозуміти?
Ro Yo Mi

-4

Для тих, хто знає трохи сценаріїв дій, ви можете з мінімальними зусиллями перевірити наявність флеш-плеєра та зробити попередній завантажувач, що також можна експортувати в html5 / Javascript / Jquery. Щоб використовувати, якщо флеш-плеєр не виявлено, перегляньте приклади, як це зробити за допомогою ролі youtube назад до html5-програвача :) І створіть свій власний. У мене немає деталей, тому що я ще не почав, якщо я не забув, я опублікую його пізніше і спробую якийсь нестандартний код Jquery для мого.


Це не рішення. Браузер за замовчуванням не підтримує програвач Flash. Це можна легко досягти за допомогою JavaScript, який є рідною мовою браузера.
Усман Ахмед

Я пам’ятаю ненависників Flash з 2012 року ... це було не нормально ... скрізь, де я ходив, на мене нападали, коли я навіть використовував слово Flash.
Пітер Группелаар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.