您无法控制事情的时机,以这种方式可靠地按照您尝试这样做的方式进行工作。这里的秩序的事情发生了:
- 浏览器获取的HTML页面
- 浏览器开始解析HTML
- 它找到一个
<img>
标签,它触发关闭加载src
URL的请求。
- 浏览器发现src URL无法加载,从而触发
onerror
处理程序。
- 您的JavaScript运行并安装
onerror
处理程序。
现在,步骤4和步骤5的顺序完全与时间有关并且不受您的控制。有些情况可能会导致它按照这种顺序发生,而4和5的某些情况则会发生逆转。并且请记住,一旦您的页面被加载一次,其中的一部分可能会被缓存,并且后续加载中的时序可能会有所不同。某些浏览器甚至可能缓存URL当前无法访问的事实,并且如果它立即再次请求(从而生成立即的错误响应),则可能会避免再次尝试它。
此外,当.src
属性设置为新值时,某些浏览器的行为完全不正确。几年前,我知道某些浏览器在更改.src
属性并加载新映像时并未可靠地触发onload
事件。对于onerror
处理程序也是如此。我的经验是,他们可以可靠地为第一次图像加载工作,但我不确定他们在设置不同的.src
属性时可靠地工作。
要设置一个不会错过的错误处理程序,必须在.src
属性被设置或解析之前使用它。这有两种方法可以做到这一点。
- 将使用onerror处理程序的HTML本身,以便它是
<img>
标签的一部分。
- 在您的HTML中没有完全形成
<img>
标签(例如,src或不在HTML中),然后用你的javascript,你可以添加onerror处理程序,然后创建图像或适当地设置.src
。
关键是onerror
处理程序必须在以任何方式设置.src
属性之前安装。
解决方案#1是这样的:实现的解决方案#2
<img src="xxx.jpg" onerror="setErrorImage(this)">
// this function must be in the global scope
function setErrorImage(img) {
// clear error handler so no chance of looping
img.onerror = function() {};
img.src = base_url() + 'assets/images/placeholder.jpg';
}
一种方法是这样的:
<img data-src="xxx.jpg">
(function() {
function setErrorImage() {
this.removeEventListener("error", setErrorImage);
this.src = base_url() + 'assets/images/placeholder.jpg';
}
var imgElements = document.getElementsByTagName('img');
var img, url;
for (var i = 0; i < imgElements.length; i++) {
img = imgElements[i];
// now that onerror handler is in place, set the .src property
url = img.getAttribute("data-src")
if (!img.src && url) {
img.addEventListener("error", setErrorImage);
img.src = url;
}
}
})();
你也可以没有<img>
标签在HTML不惜一切创造所有这些动态通过JavaScript动态,确保在设置.src
属性之前安装了onerror处理程序,但这往往会使设计过程更复杂一些。对于选项#2,上述解决方案通常优先于完全以代码形式创建图像对象。
您正在使用'i',但它不是一个闭包变量,因此它将包含循环中的最后一个值。 – Barmar
我已经改变它传递对象'imgElements [i]',它仍然导致相同的功能。 –
其实,这不相关。你没有在回调函数中使用'i'。我不明白你为什么把所有这些IIFE放在首位,他们只是让代码更加混乱。 – Barmar