在阅读了其他人的问题之后,我想
window.onload=...
我希望有人能回答我的问题。我已经尝试过这个方法,但它会在页面加载后立即执行代码(而不是在图片加载后执行)。
如果图像来自 CDN 并且不是相对路径,是否有任何区别?
有人知道解决方案吗?(我没有使用 jQuery)
在阅读了其他人的问题之后,我想
window.onload=...
我希望有人能回答我的问题。我已经尝试过这个方法,但它会在页面加载后立即执行代码(而不是在图片加载后执行)。
如果图像来自 CDN 并且不是相对路径,是否有任何区别?
有人知道解决方案吗?(我没有使用 jQuery)
想要一个一句话描述吗?
Promise.all(Array.from(document.images).filter(img => !img.complete).map(img => new Promise(resolve => { img.onload = img.onerror = resolve; }))).then(() => {
console.log('images finished loading');
});
相当向后兼容,即使在Firefox 52和Chrome 49(Windows XP时代)中也能工作。但不支持IE11。
如果要缩小图像列表,请使用 document.querySelectorAll(...)
替换 document.images
。
它使用 onload
和 onerror
以简便为主。如果页面上这些 img
元素的处理程序也在其他地方设置了(不太可能,但无论如何),这可能会与页面上的其他代码发生冲突。如果您不确定页面是否使用它们并希望安全,请将部分 img.onload = img.onerror = resolve;
替换为更长的一部分: img.addEventListener('load', resolve); img.addEventListener('error', resolve);
。
它还没有测试所有图像是否成功加载(即没有损坏的图像)。如果需要此功能,则可以使用以下更高级的代码:
Promise.all(Array.from(document.images).map(img => {
if (img.complete)
return Promise.resolve(img.naturalHeight !== 0);
return new Promise(resolve => {
img.addEventListener('load', () => resolve(true));
img.addEventListener('error', () => resolve(false));
});
})).then(results => {
if (results.every(res => res))
console.log('all images loaded successfully');
else
console.log('some images failed to load, all finished loading');
});
它会等待所有图片加载或加载失败。
如果你想尽早失败,使用第一张损坏的图片:
Promise.all(Array.from(document.images).map(img => {
if (img.complete)
if (img.naturalHeight !== 0)
return Promise.resolve();
else
return Promise.reject(img);
return new Promise((resolve, reject) => {
img.addEventListener('load', resolve);
img.addEventListener('error', () => reject(img));
});
})).then(() => {
console.log('all images loaded successfully');
}, badImg => {
console.log('some image failed to load, others may still be loading');
console.log('first broken image:', badImg);
});
最近的两个代码块使用naturalHeight
来检测已经加载的图像中是否有损坏的图像。这种方法通常有效,但有一些缺点:当图像URL通过CSS content
属性设置,并且图像是未指定尺寸的SVG时,据说该方法不起作用。 如果是这种情况,您需要重构代码,以便在图像开始加载之前设置事件处理程序。 这可以通过在HTML中直接指定onload
和onerror
或通过在JavaScript中创建img
元素来完成。另一种方法是在HTML中将src
设置为data-src
,并在附加处理程序后执行img.src = img.dataset.src
。
<img>
处于completed === false
状态的无限期问题,因为从未尝试加载图像,因为协议是未知的。例如,<img src="aaaa:">
。您的代码仍然有效,因为会触发onerror
,但是当您动态运行代码时,它会失败。我在这里制作了一个演示(http://jsfiddle.net/f9ku7jn4/)。也许是Firefox的一个错误? - phil294img.onload = img.onerror = resolve
看起来和 if( img.onload && img.onerror) resolve()
的效果相同? - user3746571以下是一种适用于现代浏览器的快速解决方案:
var imgs = document.images,
len = imgs.length,
counter = 0;
[].forEach.call( imgs, function( img ) {
if(img.complete)
incrementCounter();
else
img.addEventListener( 'load', incrementCounter, false );
} );
function incrementCounter() {
counter++;
if ( counter === len ) {
console.log( 'All images loaded!' );
}
}
当所有图片都加载完成后,控制台会显示"All images loaded!"。
这段代码的作用:
incrementCounter
函数incrementCounter
函数将增加计数器以跨浏览器的方式实现这段代码并不是特别难,只是这样写更加清晰。
Promise模式将以最佳方式解决此问题。我参考了一个开源库when.js来解决所有图像加载的问题。
function loadImage (src) {
var deferred = when.defer(),
img = document.createElement('img');
img.onload = function () {
deferred.resolve(img);
};
img.onerror = function () {
deferred.reject(new Error('Image not found: ' + src));
};
img.src = src;
// Return only the promise, so that the caller cannot
// resolve, reject, or otherwise muck with the original deferred.
return deferred.promise;
}
function loadImages(srcs) {
// srcs = array of image src urls
// Array to hold deferred for each image being loaded
var deferreds = [];
// Call loadImage for each src, and push the returned deferred
// onto the deferreds array
for(var i = 0, len = srcs.length; i < len; i++) {
deferreds.push(loadImage(srcs[i]));
// NOTE: We could push only the promise, but since this array never
// leaves the loadImages function, it's ok to push the whole
// deferred. No one can gain access to them.
// However, if this array were exposed (e.g. via return value),
// it would be better to push only the promise.
}
// Return a new promise that will resolve only when all the
// promises in deferreds have resolved.
// NOTE: when.all returns only a promise, not a deferred, so
// this is safe to expose to the caller.
return when.all(deferreds);
}
loadImages(imageSrcArray).then(
function gotEm(imageArray) {
doFancyStuffWithImages(imageArray);
return imageArray.length;
},
function doh(err) {
handleError(err);
}
).then(
function shout (count) {
// This will happen after gotEm() and count is the value
// returned by gotEm()
alert('see my new ' + count + ' images?');
}
);
window.onload
不起作用,因为它只在页面加载完毕后触发,然而图片并不包括在这个“已加载”的定义中。我一直在寻找这样的东西,如果您不介意使用 setInterval,那么这段代码非常简单明了。在我的情况下,我可以使用 setInterval,因为它可能只会运行4-5次。
const interval = setInterval(() => {
const allImagesLoaded = [...document.querySelectorAll('img')]
.map(x => x.complete)
.indexOf(false) === -1;
if (allImagesLoaded) {
window.print();
clearInterval(interval);
}
}, 500);
let imgs = document.querySelectorAll("img"),
counter = 0;
// Loop through images/check if it's loaded/if it is, increment the counter/else listen for when it does load and increment then
imgs.forEach((img) => (img.complete ? incrementCounter() : img.addEventListener("load", incrementCounter, false)));
function incrementCounter() {
counter++;
// If at least 1 image is loaded, do something
if (counter !== 0) {
calculateHeight();
}
}
<title>Pre Loading...</title>
</head>
<style type="text/css" media="screen"> html, body{ margin:0;
padding:0; overflow:auto; }
#loading{ position:fixed; width:100%; height:100%; position:absolute; z-index:1; ackground:white url(loader.gif) no-repeat center; }**
</style>
<script> function loaded(){
document.getElementById("loading").style.visibility = "hidden"; }
</script>
<body onload="loaded();"> <div id="loading"></div>
<img id="img" src="avatar8.jpg" title="AVATAR" alt="Picture of Avatar
movie" />
</body>
我正要建议和Baz1nga说的一样。
另外,还有一个可能不是那么百分之百可靠但更容易维护的选择,就是选择最重要/最大的图像,并仅对该图像附加onload事件。 这里的优点是,如果您以后向页面添加更多图像,则需要更改的代码较少。
这个非常好用:
$(function() {
$(window).bind("load", function() {
// code here
});
});