ajax - check images have loaded before writing to the page
I have a bit of a problem that I have just found, after I thought this project had finished. It worked perfectly on my local server but when I pushed the code live the images can take half a second to load properly causing a little page thumbnail to pop up over a loading image. grrr
So whats happening? Well first off a function runs on window.load
which created a large number of list items with a loading gif 开发者_StackOverflow中文版as the bg image.
Then this function pops an <img>
tag into the first list item, with an onload
which calls a second function
This second function cycles through an XML file and wraps the URL in the xml in an <img>
tag and puts it in the next empty LI
. this is where the problem lies. At the moment it puts the <img src=$variable onload=loadnextimage() />
into the List item before it has actually loaded.
My code:
$(window).load(function() {
txt="";
for(d=0;d<100;d++)
{
txt=txt + "<li class='gif' id='loading"+d+"'></li>";
}
document.getElementById('page-wrap').innerHTML=txt;
document.getElementById('loading0').innerHTML="<img src='images/0.jpg' onLoad='loadImages(0)' />";
});
function loadImages(i){
i++
$.ajax
({
type: "GET",
url: "sites.xml",
dataType: "xml",
async: "true",
success: function(xml)
{
var img = $(xml).find('image[id=' + i + ']'),
id = img.attr('id'),
url = img.find('url').text();
$('#loading'+i).html('<img src="'+url+'" onLoad="loadImages('+i+')" />').hide();
$('#loading'+i).fadeIn();
}
});
}
I have a feeling it may be quite tricky achieving this how I have it set up, and I have a feeling i may need to create an img object and wait for that to load???
Once the page is cached the loading obviously works fine but its a bit of a pain ont he first load so i need to fix this. any advise welcome :) thanks
In my opinion, you are thinking in a hard way. Sometimes solution is in changing the way of thinking. It is completely depends on you. One of my favorite related books.
My suggestion is have something like the code below. It's not exactly what you need but...
Demo on Fiddle
HTML:
<div class="frame" title="Tochal Hotel">
<div class="loadingVitrin">
<img src="http://photoblog.toorajam.com/photos/4cf85d53afc37de7e0cc9fa207c7b977.jpg" onload="$(this).fadeTo(500, 1);">
</div>
</div>
CSS:
html, body {
padding: 10px;
}
.frame {
z-index: 15;
box-shadow: 0 0 10px gray;
width: 350px;
height: 350px;
border: gray solid 1px;
padding: 5px;
background: #F0F9FF;
}
.loadingVitrin {
z-index: 15;
width: 350px;
height: 350px;
overflow: hidden;
background: url("http://photoblog.toorajam.com/images/main/ajax-loader.gif") no-repeat center;
}
.loadingVitrin img {
display: none;
height: 350px;
}
success: function(xml) {
var img = $(xml).find('image[id=' + i + ']'),
id = img.attr('id'),
url = img.find('url').text();
// hide loading
$('#loading'+i).hide();
$('<img src="'+url+'" onLoad="loadImages('+i+')" />').load(function() {
// after image load
$('#loading' + i).html(this); // append to loading
$('#loading'+i).fadeIn(); // fadeIn loding
});
}
I had the same problem. attempting to get an answer I reached your question. anyways the way I managed to kind of solve it was by placing:
<div style="visibility:hidden; position:absolute; margin-left:-10000px;">
<img src="foo.png" />
// place all the images in here that you eventually will need
</div>
the images will be downloaded asynchronously. if you already have an image it will not be downloaded again it will be stored in the cache of the browser. so if the user spends 30 seconds in the first page then your entire site will be much faster. well it depends on the size of your site. but this solves the problem when using a small website.
I know this is not a real solution I will start a bounty on your question.
Thanks to @thecodeparadox I ended up with:
$.get("SomePage.aspx", "", function (r) {
// r = response from server
// place response in a wrapper
var wrapper = $('<div id="wrapper" style=""></div>').html(r);
// need to write the images somewhere in the document for the event onload to fire
// loading content is a hidden div in my document.
$(document).append(wrapper);
//$("#LoadingContent").html("").append(wrapper);
var counter = 0;
var images = $(wrapper).find("img"); // get all the images from the response
// attach the onload event to all images
images.bind("load", function () {
counter++;
if (counter == images.size()) { // when all images are done loading
// we are now save to place content
// place custom code in here
// executeSomeFuction();
$("#AjaxContent").html(r);
$(document).remove(wrapper);
}
});
}, "text");
You just have to preload each images with the Image() object. The script giving below is pretty easy to use. Just write in the "callbackFN()" whatever code you wanna do and then you "preload_images(array_img)". More precisly:
var array_images = [];
$.ajax
({
type: "GET",
url: "sites.xml",
dataType: "xml",
async: "true",
success: function(xml)
{
var img = $(xml).find('image[id=' + i + ']'),
id = img.attr('id'),
url = img.find('url').text();
array_images.push(url);
}
});
// Your callback function after loading:
function callbackFN() {
// Do whatever you want HERE
// Pretty much this:
for (var i = 1; i<=array_images.length; i++) {
$('#loading'+i).html('<img src="'+url+'" />').hide();
$('#loading'+i).fadeIn();
}
}
var array_obj = Array();
var iKnowItsDone = false;
// Timer (IE BULLET PROOF)
var ieCheckImgTimer;
// Check if images are loaded
function images_complete(obj) {
var max = obj.length;
var canGo = true;
for (var i = 0; i<max; i++){
if (!obj[i].complete) {
canGo = false;
}
}
return canGo;
}
// Loop to check the images
function preload_images(obj) {
var max = obj.length;
for (var i = 0; i<max; i++){
var img = new Image();
img.src = obj[i];
array_obj.push(img);
img.onload = function() {
check_img();
}
}
ieCheckImgTimer = setTimeout('check_img()',250);
}
// Timer to see if all the images are loaded yet. Waits till every img are loaded
function check_img() {
if (ieCheckImgTimer) {
clearTimeout(ieCheckImgTimer);
}
if (images_complete(array_obj) && !iKnowItsDone) {
iKnowItsDone = true;
callbackFN();
}
else {
ieCheckImgTimer = setTimeout('check_img()',250);
}
}
Try This:
ThumbImage = document.createElement("img");
ThumbImage.src = URL;
ThumbImage.onload = function(){
//function After Finished Load
}
You want to make sure the image is loaded by the browser, i.e. in the browser's cache, before adding it to the document:
// create an image element
$('<img />')
// add a load event handler first
.load(function() {
// append the image to the document after it is loaded
$('#loading').append(this);
})
// then assign the image src
.attr('src', url);
So for your code I would do:
$(window).load(function() {
var txt="";
for(var d=0;d<100;d++)
{
txt=txt + "<li class='gif' id='loading"+d+"'></li>";
}
document.getElementById('page-wrap').innerHTML=txt;
$('<img />')
.load(function() {
$('#loading0').append(this);
loadImages(0);
})
.attr('src', 'images/0.jpg');
});
function loadImages(i){
i++
$.ajax
({
type: "GET",
url: "sites.xml",
dataType: "xml",
async: "true",
success: function(xml)
{
var img = $(xml).find('image[id=' + i + ']'),
id = img.attr('id'),
url = img.find('url').text();
$('<img />')
.load(function() {
$('#loading' + i)
.append(this)
.hide()
.fadeIn();
loadImages(i);
})
.attr('src', url);
}
});
}
Maybe it's just your sample code, but I don't see why 0.jpg and sites.xml, or the rest of the images, can't be loaded at the same time:
$(window).load(function() {
var buf = [], d;
for (d = 0; d < 100; d++) {
buf.push('<li class="gif" id="loading' + d + '"></li>');
}
$('#page-wrap').html(buf.join(''));
$('<img />')
.load(function() {
$('#loading0').append(this);
})
.attr('src', 'images/0.jpg');
$.ajax({
type: 'GET',
url: 'sites.xml',
dataType: 'xml',
async: true,
success: function(xml) {
var img, id, url, i;
xml = $(xml);
for (i = 1; i < 100; i++) {
img = xml.find('image[id=' + i + ']');
id = img.attr('id');
url = img.find('url').text();
$('<img />')
.load(function() {
$('#loading' + i)
.append(this)
.hide()
.fadeIn();
})
.attr('src', url);
}
}
});
});
精彩评论