Предварительная загрузка изображений с помощью jQuery

642

Я ищу быстрый и простой способ предварительной загрузки изображений с помощью 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});
Теги:

20 ответов

981
Лучший ответ

Быстро и просто:

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();
  • 0
    Почему этот код не работает для меня? Это работает для других?
  • 25
    Не нужно ли вставлять элемент изображения в DOM, чтобы браузер кешировал его?
Показать ещё 22 комментария
98

Здесь есть исправленная версия первого ответа, который фактически загружает изображения в DOM и скрывает его по умолчанию.

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}
  • 37
    hide() является более кратким, чем css('display', 'none') .
  • 0
    Это прекрасно работает, когда я пытаюсь сделать это в Firefox, но не с IE9.
Показать ещё 6 комментариев
48

Использовать 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 object. Вы видели, как люди поступали неправильно в этих ответах?
  • 0
    Блестящий код. Правильно ли я считаю, что это вызовет событие onload даже если изображение кэшируется? (Потому что img.onload объявляется первым). Это то, что показали мои тесты.
Показать ещё 16 комментариев
31

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

В основном я добавил обратный вызов в ваш предварительный плагин 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 и в функции onload: checklist-- Then: if (checklist == 0) callback();
  • 3
    Все было бы хорошо, однако добавление новых или удаление существующих методов для объекта, которым вы не владеете, является одной из худших практик в JavaScript.
Показать ещё 2 комментария
23

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

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

  • 0
    @Manticore исправил это ...
  • 0
    Это действительно хороший ответ, он действительно должен быть самым популярным.
Показать ещё 1 комментарий
19

У меня есть небольшой плагин, который обрабатывает это.

Он называется waitForImages и может обрабатывать элементы img или любой элемент со ссылкой на изображение в CSS, например. div { background: url(img.png) }.

Если вы просто захотите загрузить все изображения, в том числе ссылки, указанные в CSS, вот как вы это сделаете:)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});
  • 0
    Этот плагин вызывает загрузки изображений, которые еще не появились на странице, или только прикрепляет события к изображениям, которые уже были загружены?
  • 0
    @DaveCameron Не имеет значения, являются ли изображения видимыми или нет. Вы можете легко его раскошелиться и внести это изменение - просто добавьте :visible для пользовательского селектора.
Показать ещё 4 комментария
13

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

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

example: 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 не является хорошей причиной для того, чтобы изображения занимали несколько миллисекунд для загрузки на странице +, вы должны анализировать и выполнять миллисекунды для script, если они большие изображения, поэтому их скрытие в hml лучше также для производительности, потому что изображение действительно предварительно загружено без видимой видимости, пока вы не покажете это!

  • 2
    Более подробную информацию об этом подходе можно найти здесь: perishablepress.com/…
  • 3
    Но вы должны знать, что этот метод имеет существенный недостаток: ваша страница не будет полностью загружена, пока не будут загружены все изображения. В зависимости от количества загружаемых изображений и их размера, это может занять некоторое время. Еще хуже, если тег <img> не определяет высоту и ширину, некоторые браузеры могут подождать, пока изображение будет извлечено, прежде чем отображать остальную часть страницы.
Показать ещё 4 комментария
13

этот jquery imageLoader плагин всего 1,39kb

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

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

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

  • 10
    неправильное использование $ (document) .ready внутри обратного вызова: |
  • 0
    @AamirAfridi Почему это?
Показать ещё 6 комментариев
8

Быстрый, без плагинов способ предварительной загрузки изображений в 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

Спасибо за это! Я хотел бы добавить немного риффа в ответ 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

Я использую следующий код:

$("#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";
  • 0
    Сначала привяжите к событию load, затем установите src.
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
    Добро пожаловать в стек переполнения! Вместо того, чтобы только публиковать блок кода, пожалуйста, объясните, почему этот код решает поставленную проблему. Без объяснения это не ответ.
1

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

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

0

Я хотел сделать это с помощью пользовательского наложения API Карт Google. Их примерный код просто использует JS для вставки IMG-элементов, а поле-заполнитель изображения отображается до загрузки изображения. Я нашел здесь ответ, который работал на меня: https://stackoverflow.com/questions/10863658/load-image-with-jquery-and-append-it-to-the-dom.

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

Предварительно загружает изображение, как было предложено ранее, а затем использует обработчик для добавления объекта img после загрузки URL-адреса. Документация jQuery предупреждает, что кешированные изображения плохо работают с этим кодом eventing/handler, но он работает для меня в FireFox и Chrome, и мне не нужно беспокоиться об IE.

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

Это работает для меня даже в IE9:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });
  • 1
    Это в конечном итоге не удастся из-за кэширования, всегда связывайте событие загрузки перед установкой атрибута src.
-2

5 строк в coffeescript

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
    Можете ли вы рассказать о том, как работает решение для решения вопроса в ОП? И, возможно, прокомментируйте свой код, чтобы другие могли легче его понять?
-2
function preload(imgs) {
$(imgs).each(function(index, value){
        $('<img />').attr('src',value).appendTo('body').css('display','none');
    });
}

.attr('src',value)

не

.attr('src',this)

чтобы указать на это:)

  • 0
    Область действия this внутри обратного вызова, который передается в $.each , присваивается значению, которое повторяется.
  • 0
    ? $ (['img1.jpg', 'img2.jpg', 'img3.jpg']). each (function (index, value) {console.log (value); // img1.jpg console.log (this) ; // String {0 = "i", 1 = "m", 2 = "g", more ...} $ ('<img />'). Attr ('src', this) .appendTo (' body '). css (' display ',' none ');});
Показать ещё 1 комментарий
-4

Для тех, кто знает немного ActionScript, вы можете проверить флеш-плеер с минимальными усилиями и сделать предварительный загрузчик Flash, который вы также можете экспортировать в html5/Javascript/Jquery. Чтобы использовать, если флеш-плеер не обнаружен, проверьте примеры того, как это сделать с ролью youtube обратно в html5 player:) И создайте свой собственный. У меня нет деталей, потому что я еще не начал, если я не забуду, я позже отправлю его позже и попробую запустить какой-то стандартный код JQuery для моего.

  • 0
    Это не решение. Браузер не поддерживает Flash player по умолчанию. Этого легко добиться с помощью JavaScript, который является родным языком браузера.
  • 0
    Кто говорит о Flash? .. где вы, ребята, были ...
Показать ещё 1 комментарий
-6

Все хипстеры писали там собственную версию, так что вот моя. Он добавляет скрытый div в тело и заполняет его необходимыми изображениями. Я написал это в Coffee Script. Здесь Кофе, нормальный js и сжатые js.

Кофе

$.fn.preload = () ->
    domHolder = $( '<div/>' ).hide()
    $( 'body' ).append domHolder
    this.each ( i, e) =>
        domHolder.append( $('<img/>').attr('src', e) )

Normal:

(function() {

  $.fn.preload = function() {
    var domHolder,
      _this = this;
    domHolder = $('<div></div>').css('display', 'none');
    $('body').append(domHolder);
    return this.each(function(i, e) {
      return domHolder.append($('<img/>').attr('src', e));
    });
  };

}).call(this);

Сжатый:

function(){$.fn.preload=function(){var a,b=this;return a=$("<div></div>").css("display","none"),$("body").append(a),this.each(function(b,c){return a.append($("<img/>").attr("src",c))})}}.call(this);
  • 1
    используйте '<div/>' и .hide() вместо .css('display', 'none')
  • 0
    Так много кода для такой простой задачи

Ещё вопросы

Сообщество Overcoder
Наверх
Меню