>假设我有一个div,并且想向该div注入一些HTML。HTML 将包含 1 个或多个图像。
有没有办法用普通的JavaScript或jQuery来确定图像何时加载?
因此,如果我执行以下操作,您能否将事件侦听器放在单个元素上以告知内容(包括图像(何时准备就绪?
var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
$("div.output").html(html);
图像每次都会不同,所以我无法使用 JavaScript 图像对象预加载。
我想做的一种方法是使用正则表达式或jQuery运行HTML,找到所有图像URL,循环访问它们并使用图像对象预加载每个URL。当所有内容都已预加载后,将 HTML 注入到输出div 中。
加载之前将onload
事件挂接到每个图像并对其进行计数,否则没有简单的方法可以判断它们何时全部加载。
这是一个相对防弹的方法(demo(,它使用Deferred
s,在IE 6-9,Chrome 19和Firefox 3.6-10,Opera 10.10-11.52,Android 4和iOS 5中测试和工作。
首先,我们将编写一个小的 jQuery 插件,它为 jQuery 集合中的每个元素返回一个 Deferred
的数组。 每个Deferred
将在元素加载时解析;如果元素加载失败或(可选(花费的时间超过 timeout
秒,则被拒绝。
$.fn.loaded = function(opts) {
var o = $.extend({timeout:10000}, opts) // Merge default options with supplied options
, r = []; // Return value
this.each(function() {
var dfd = new $.Deferred(), el = $(this), to;
if (o.timeout) to = setTimeout(function() {
done();
dfd.reject();
}, o.timeout);
el.bind('load.dfdl', function() {
done();
dfd.resolve();
}).bind('error.dfdl', function() {
done();
dfd.reject();
});
function done() { // internal clean-up
clearTimeout(to);
el.unbind('.dfdl');
}
r.push(dfd.promise());
});
return r;
};
超时将防止浏览器从未实际触发任何事件的情况。 我在这里将默认超时设置为 10 秒;在现实世界中,您可能希望减少这种情况。
现在,我们将生成 10 个随机大小的 placekit,以用作示例中的图像。
var imgs=[];
for (var i = 0; i < 10; i++) imgs.push('<img src="http://placekitten.com/' + rnd() + '/' + rnd() + '"> ');
$('#imgs').html(imgs.join());
最后,我们将把所有东西和一些魔法放在一起:
$.when.apply($, $('#imgs img').loaded({timeout:10000}) ).done(function() {
alert('loaded successfully');
}).fail(function() {
alert('load failed or timed out');
});
$.when
创建一个主Deferred
,该主仅在其所有子Deferred
解析时解析,或在子项拒绝时拒绝。 它通常希望您将每个Deferred
作为参数传递(它不支持传入 Deferred
的数组(,因此我们必须apply
数组。 (我可能会做$.whenall = function(dfds) { $.when.apply($,dfds); };
,以便您的应用程序代码具有更干净的$.whenall( $('#imgs img').loaded() )...
(
试试这个:
$("#preload_div").html(
'<img src="image.png" alt="preload" class="preload" width="0" height="0">'
);
事件处理程序可以绑定到映像:
$('preload').load(function () {
var html = "<p>Some text <img src='image.jpg' /></p><p>Some more text <img src='image2.jpg' /></p>";
$("div.output").html(html);
});
当然,您必须为每个图像合并一个 .each(( 才能遍历所有图像。
编辑:在我的一个AJAX网站上,我预加载了我需要的下一个图像,因此当用户单击"下一步"按钮时,新内容所需的图像已经缓存。请参阅 http://funl.es/p/1
我想做的一种方法是使用正则表达式或jQuery运行HTML,找到所有图像URL,循环访问它们并使用图像对象预加载每个URL。当所有内容都已预加载后,将 HTML 注入到输出div 中。
var imagesLoaded = [];
var imagesErrored = [];
$('img').each(function() {
$(this).load(function() {
imagesLoaded.push($(this).attr("src"));
if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
displayResults(imagesLoaded, imagesErrored);
}
});
$(this).error(function() {
imagesErrored.push($(this).attr("src"));
if( (imagesLoaded.length + imagesErrored.length) == $('img').length ) {
displayResults(imagesLoaded, imagesErrored);
}
});
function displayResults(imagesLoaded, imagesErrored) {
for(var i = 0; i < imagesLoaded.length; i++) {
alert(imagesLoaded[i] + " has loaded successfully.");
$('#myDiv').append("<img src='" + imagesLoaded[i] + "' />");
}
for(var i = 0; i < imagesErrored.length; i++) {
alert(imagesLoaded[i] + " did NOT load successfully.");
}
}
上面的内容循环遍历所有图像,并使用 load 事件检查它们是否加载。使用 error 事件,我们还获得了由于某种原因未正确加载的所有图像的集合。预加载所有图像后,我们可以在"displayResults"函数中将它们注入到页面上。这大致基于您问题的最后一段。
但是,它不使用正则表达式,因为它们不是操作 DOM 的正确工具。 幸运的是,JavaScript 和 jQuery 为我们提供了执行 DOM 操作和解析活动所需的工具。
最后,从您的问题来看,听起来您可能有兴趣了解哪些图像已成功加载。如果需要,从加载和错误事件生成的上述集合将为您提供这些详细信息。
我认为您应该在将图像插入 html 后绑定加载处理程序。
演示
//Add image
$('#result').append('<img src= "<Your_Image_URL>" width="300" height="300"/>');
//Bind handler also add condition to not bind images that was not added before.
$('#result').find('img').not('.loaded').on('load', function () {
alert('Image Loaded');
//Add code that you want to do after the image is added
}).addClass('loaded');
另请注意与图像一起使用时加载事件的注意事项
开发人员尝试使用 .load(( 解决的常见挑战 快捷方式是在执行函数时的图像(或集合 图像(已完全加载。有几个已知的警告 这一点应该注意。这些是:
- 它不能始终如一地工作,也不能可靠地跨浏览器
工作- 如果图像 src 设置为与以前相同的 src,则在 WebKit 中无法正确触发
- 它没有正确地冒泡 DOM 树
- 可以停止为浏览器缓存中已存在的图像触发
参考: http://api.jquery.com/load-event/
您是否考虑过使用 jQuery 'on' 事件机制?使用"on"应该允许您在动态添加到容器和 DOM 时自动将"load"处理程序绑定到每个映像。
链接: jQuery docs for 'on' 函数
如果您使用的是 1.7 之前的 jQuery,则需要使用"live"函数,因为 1.7 版本添加了"on"。
链接:用于"实时"函数的jQuery文档(已弃用(
我认为没有简单的方法可以做到这一点。您可以做的是将所有图像加载到隐藏的div上(显示:无(。
当您想显示图片时,您可以执行以下操作:
$("#myDiv").show();