Предварительная загрузка изображений с помощью JavaScript и jQuery - PullRequest
2 голосов
/ 20 сентября 2009

Я использую следующий код для вставки некоторого HTML в div и для предварительной загрузки любых изображений, которые могут содержаться в этом HTML (данные html var фактически извлекаются из запроса AJAX в реальном коде). Это сделано для того, чтобы браузер не загружал извлеченные изображения HTML при отображении div (используя событие slideDown) - потому что это приводит к нарушению плавности эффекта при загрузке изображения в середине перехода. Я полагаю, что я мог бы использовать чересстрочный JPEG, чтобы размеры изображения были известны почти сразу, но, очевидно, было бы неплохо разработать более чистый метод. : P

var html = '<img src="images/test.jpg" alt="test" />';

$('div.content').hide().html(html);

$('div.content img').each(function(){

    var img = new Image();

    img.src = $(this).attr('src');

    $(this).attr('src', img.src);

});

$('div.content').slideDown('normal');

Я использую объект Image и его последующее назначение в соответствии с приведенным советом здесь , но, к сожалению, изображение по-прежнему не кэшируется браузером с использованием этого метода, поскольку эффект sildeDown () все еще прерывается при загрузке изображения.

Любая помощь или альтернативные методы? Большое спасибо.

Редактировать - 21 сентября 09


Прогресс! Оказывается, браузер кэшировал изображение, я просто не давал ему времени для этого (ему просто нужна была секунда для загрузки с помощью alert () или setInterval ()). Теперь представьте, что, вероятно, самый грязный код из всех, что я делал - я использую бесконечный цикл для создания этой паузы.

Новый метод расширяет старый код выше, привязывая функцию (которая добавляет src каждого изображения в массив) к успешному событию загрузки этого изображения. Затем он застревает в бесконечном цикле, ожидая, пока все изображения загрузятся и, следовательно, появятся в массиве. Кажется, это работает как способ синхронной предварительной загрузки изображений, но проблема остается; цикл while () по какой-то причине циклически повторяется даже после загрузки всех изображений, , если Я не добавлю предупреждение (), чтобы приостановить его на мгновение.

Новый код:

var html = '<img src="images/test.jpg" alt="test" />';

$('div.content').hide().html(html);

// define usr variables object
$.usrvar = {};

// array of loaded images' urls
$.usrvar.images = [];

// boolean for whether this content has images (and if we should check they are all loaded later)
$.usrvar.hasimages = false;

// foreach of any images inside the content
$('div.content img').each(function(){

    // if we're here then this content has images..
    $.usrvar.hasimages = true;

    // set this image's src to a var
    var src = $(this).attr('src');

    // add this image to our images array once it has finished loading
    $(this).load(function(){

        $.usrvar.images.push(src);

    });

    // create a new image
    var img = new Image();

    // set our new image's src
    img.src = src;

});

// avoid this code if we don't have images in the content
if ($.usrvar.hasimages != false) {

    // no images are yet loaded
    $.usrvar.imagesloaded = false;

    // repeatedly cycle (while() loop) through all images in content (each() loop)
    while ($.usrvar.imagesloaded != true) {

        $('div.content img').each(function(){

            // get this loop's image src
            var src = $(this).attr('src');

            // if this src is in our images array, it must have finished loading
            if ($.usrvar.images.indexOf(src) != -1) {

                // set imagesloaded to trueai
                $.usrvar.imagesloaded = true;

            } else {

                // without the pause caused by this alert(), this loop becomes infinite?!
                alert('pause');

                // this image is not yet loaded, so set var to false to initiate another loop
                // (ignores whether imagesloaded has been set to true by another image, because ALL
                // need to be loaded
                $.usrvar.imagesloaded = false;

            }

        });

    }

}

$('div.content').slideDown('normal');

Ответы [ 4 ]

1 голос
/ 21 сентября 2009

Я сделал следующее решение, но оно не было проверено, поэтому вы предупреждены;)

// HTML (any formatting possible)
// no src for the images: it is provided in alt which is of the form url::actualAlt
var html = "<p><img alt='images/test.jpg::test' /><br />Some Text<br /><img alt='images/test2.jpg::test2' /></p>";

$(document).ready(function() {

    // Reference to the content div (faster)
    var divContent = $("div.content");

    // Hide the div, put the HTML
    divContent.hide().html(html);

    // Webkit browsers sometimes do not parse immediately
    // The setTimeout(function,1) gives them time to do so
    setTimeout(function() {

        // Get the images
        var images = $("img",divContent);

        // Find the number of images for synchronization purpose
        var counter = images.length;

        // Synchronizer
        // will show the div when all images have been loaded
        function imageLoaded() {
            if (--counter<=0) $('div.content').slideDown('normal');
        }

        // Loading loop
        // For each image in divContent
        $.each(images,function() {
            // Get the url & alt info from the alt attribute
            var tmp = $(this).attr("alt").split("::");
            // Set the alt attribute to its actual value
            $(this).attr("alt",tmp[1]);
            // Wire the onload & onerror handlers
            this.onload = this.onerror = imageLoaded;
            // Set the image src
            this.src = tmp[0];
        });

    },1);

});
0 голосов
/ 20 мая 2011

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

    var myImgs = ['images/nav/img1.png', 'images/nav/img2.png', 'images/nav/img3.png', 'images/nav/img4.png', 'images/expand.png', 'images/collapse.png'];

    function preload(imgs) {
        var img;
        for (var i = 0, len = imgs.length; i < len; ++i) {
            img = new Image();
            img.src = imgs[i];
        }
    }

    preload(myImgs);
0 голосов
/ 15 июля 2010

Я играл с этим и создал немного другое решение. Вместо того, чтобы помещать изображения в массив, когда они загружаются, вы помещаете их все в массив в цикле, затем в событии загрузки вы удаляете их из массива и вызываете «готовую» функцию. Он проверяет, является ли массив изображений пустым, и если это так, то очищается и показывает содержимое.

var html = '< animg src="images/test.jpg" alt="test" />'; // not allowed to post images...

$('div.content').hide().html(html);

// preload images

// define usr variables object
$.usrvar = {};      
// array of loaded images' urls
$.usrvar.images = [];
// initially no images      
$.usrvar.hasimages = false;
$('div.content img').each(function() {
    // if we're here then this content has images..
    $.usrvar.hasimages = true;
    // set this image's src to a var
    var src = this.src;
    // add this image to our images array
    $.usrvar.images.push(src);
    // callback when image has finished loading
    $(this).load(function(){
        var index = $.usrvar.images.indexOf(src);
        $.usrvar.images.splice(index,1);
        finish_loading();
    });
    // create a new image
    var img = new Image();
    // set our new image's src
    img.src = src;
});
if(!$.usrvar.hasimages) finish_loading();

function finish_loading() {
    if($.usrvar.hasimages) {
        if($.usrvar.images.length > 0) return;
    }
    $('div.content').slideDown('normal');
}

Редактировать: Глядя на пост Жюльена, его метод лучше. Мой метод работает аналогичным образом, но, как и в оригинальном решении, он отслеживает изображения с помощью массива srcs, а не просто подсчета (что более эффективно).

Редактировать 2: ну, я подумал, что это лучшее решение, но, похоже, оно не работает для меня. Возможно, это связано с тем, что событие load вызывается слишком близко друг к другу. Иногда это работает, но иногда зависает при загрузке изображений, и счетчик изображений никогда не достигает нуля. Я вернулся к методу в моем посте выше.

Редактировать 3: Похоже, что именно setTimeout вызывал проблему.

0 голосов
/ 20 сентября 2009

Создайте интервал / тайм-аут и дайте ему проверить ваш compterGenerated css-height, если он автоматически изменяет размер, он начинается с 0 и заканчивается до 100 (например). Но в Safari он загружает высоту перед изображением, поэтому, вероятно, он не будет работать во всех браузерах ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...