在 JavaScript 中检测图像何时加载失败

是否有一种方法可以确定图像路径是否导致实际的图像,即检测图像何时无法在 JavaScript 中加载。

对于一个 web 应用程序,我解析一个 xml 文件,并从图像路径列表中动态创建 HTML 图像。一些图像路径可能不再存在于服务器上,所以我想通过检测哪些图像无法加载并删除该 HTML img 元素来优雅地失败。

注意,jQuery 解决方案不能使用(老板不想使用 jQuery,是的,我知道不要让我开始)。我知道在 jQuery 中有一种方法可以检测图像何时加载,但不能检测图像是否失败。

我创建 img 元素的代码,但是如何检测 img 路径是否导致加载图像失败?

var imgObj = new Image();  // document.createElement("img");
imgObj.src = src;
152965 次浏览

这是我为另一个答案写的函数: 图像网址验证。我不知道它是否正是您所需要的,但是它使用了您将使用的各种技术,包括 onloadonerroronabort和一般超时的处理程序。

因为图像加载是异步的,所以您可以用图像调用这个函数,然后稍后它会用结果调用您的回调函数。

你可以试试下面的代码。不过我不能保证浏览器的兼容性,所以你必须测试一下。

function testImage(URL) {
var tester=new Image();
tester.onload=imageFound;
tester.onerror=imageNotFound;
tester.src=URL;
}


function imageFound() {
alert('That image is found and loaded');
}


function imageNotFound() {
alert('That image was not found.');
}


testImage("http://foo.com/bar.jpg");

我同情这个不能使用 jQuery 的老板!

如下:

var img = new Image();
img.src = imgUrl;


if (!img.complete) {


//has picture
}
else //not{


}

答案是好的,但它引入了一个问题。无论何时直接分配 onloadonerror,它都可以替换先前分配的回调。这就是为什么有一个很好的方法,“在调用它的 EventTarget 上注册指定的侦听器”,因为他们说在 MDN。您可以在同一事件上注册任意多个侦听器。

让我重写一下答案。

function testImage(url) {
var tester = new Image();
tester.addEventListener('load', imageFound);
tester.addEventListener('error', imageNotFound);
tester.src = url;
}


function imageFound() {
alert('That image is found and loaded');
}


function imageNotFound() {
alert('That image was not found.');
}


testImage("http://foo.com/bar.jpg");

因为外部资源加载过程是异步的,所以使用带有承诺的现代 JavaScript 会更好,如下所示。

function testImage(url) {


// Define the promise
const imgPromise = new Promise(function imgPromise(resolve, reject) {


// Create the image
const imgElement = new Image();


// When image is loaded, resolve the promise
imgElement.addEventListener('load', function imgOnLoad() {
resolve(this);
});


// When there's an error during load, reject the promise
imgElement.addEventListener('error', function imgOnError() {
reject();
})


// Assign URL
imgElement.src = url;


});


return imgPromise;
}


testImage("http://foo.com/bar.jpg").then(


function fulfilled(img) {
console.log('That image is found and loaded', img);
},


function rejected() {
console.log('That image was not found');
}


);
/**
* Tests image load.
* @param {String} url
* @returns {Promise}
*/
function testImageUrl(url) {
return new Promise(function(resolve, reject) {
var image = new Image();
image.addEventListener('load', resolve);
image.addEventListener('error', reject);
image.src = url;
});
}


return testImageUrl(imageUrl).then(function imageLoaded(e) {
return imageUrl;
})
.catch(function imageFailed(e) {
return defaultImageUrl;
});

这个:

<img onerror="this.src='/images/image.png'" src="...">

用于 img 的 jQuery + CSS

对于 jQuery,这对我很有用:

$('img').error(function() {
$(this).attr('src', '/no-img.png').addClass('no-img');
});

我可以在我的网站上的任何地方使用这张图片,不管它的大小,下面是 CSS3的属性:

img.no-img {
object-fit: cover;
object-position: 50% 50%;
}

提示1: 使用至少800x800像素的 正方形图像正方形图像

提示2: 对于与 人物肖像一起使用,使用 object-position: 20% 50%;

CSS 只适用于背景-img

对于缺少的背景图像,我还在每个 background-image声明中添加了以下内容:

background-image: url('path-to-image.png'), url('no-img.png');

注意: 不适用于透明图像。

Apache 服务器端

另一种解决方案是在发送到浏览器之前使用 Apache 检测丢失的图像,并将其替换为默认的 no-img.png 内容。

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]

这是@emil 的一个变体。C 回答,但是根据图像加载与否以 true/false 解析(而不是在失败时抛出错误) :

function testImage(url) {
if (!url || typeof url !== 'string') return Promise.resolve(false);
return new Promise((resolve) => {
const imgElement = new Image();
imgElement.addEventListener('load', () => resolve(true));
imgElement.addEventListener('error', () => resolve(false));
imgElement.src = url;
});
}

关于 Rafael Martins 的答案,如果你正在使用 React,请使用以下代码:

<img
src="https://example.com/does_not_exist.png"
onError={(e) => {
e.currentTarget.src = "https://example.com/default.png"
}}
/>