手记

IE下img标签error事件的兼容性问题

1、事件简介

现需在一个html页面中显示一张图片,这张图片的地址是通过GET方式从地址栏中传入的。但是如果图片损坏或传参错误,在部分浏览器下会出现破裂图,所以当遇到这种情况则将图片隐藏掉。

地址示例:http://example.com/test.html?s=1.jpg

据此要求编写的初始代码如下(代码中的两个console用于后续的测试):

HTML

<img src="" id="image" onerror="this.onerror='';console.log('none');this.style.display='none'">

JS

var imgSrc=GetUrlParams().s||"";   // GetUrlParams是用来获取url中的参数的,参数名为s

var img=document.getElementById("image");

if (imgSrc) {

    img.src=imgSrc+"?t="+Math.random();

    console.log('block');

    img.style.display='block';

}
2、问题探究

当用上述代码在各浏览器中进行测试时,发现在IE下图片无法显示,但从开发者工具中可以看到图片是正确请求了,去掉CSS样式后图片妥妥的躺在页面上。其它浏览器(Chrome、Opera、FireFox、Safari)表现符合预期。

之后我对IE做了一些测试,测试内容如下:

1)当不传参数时,img的error事件会被触发,控制台输出none,这一点跟其它浏览器一致;

2)当传参时,其它浏览器均不触发error事件,只有IE会触发;

按照浏览器的加载原则,图片会在其它所有代码之后加载,所以页面先获取到了图片地址参数并更新到了img标签上,然后才去加载图片。也就是说,当加载图片时,图片的地址已经是最终的那个传参了,理论上是不应该触发error事件的。

IE这个行为比较奇怪。经过一番琢磨后,我猜想IE是不是在自上而下读到img标签处时,虽然没立即加载图片,但是却把图片的地址添加到了后续的计划任务中,就好像打印机那样,然后在其它代码加载完之后陆续请求了这些地址(就像是请求了一个地址数组[“”,”1.jpg”]),而在请求空地址时触发了error事件,导致图片被隐藏了。为了验证这一猜想,我做了如下的一番测试:

① 编写了一个新的页面,功能是在初始化时,通过循环多次修改img的src属性,然后观察IE是否会对所有赋值都发起请求。

HTML

<img id="image" onload="this.style.display='block'">

JS

var img=document.getElementById("image");
var imgArr=["1.jpg","favicon.png","loading.gif"];
for (var i = 0; i < imgArr.length; i++) {img.src=imgArr[i]+"?t="+Math.random();}

测试后发现,IE的确请求了数组中所有的地址,但在变更img的src的过程中,被废弃的那些图片地址都显示挂起,应该是被中断掉了。

② 继续观察该测试页面在其它浏览器下的反应,发现Chrome、FireFox、Opera均只请求了最后那张图片的地址。

但是Safari的表现有点意外了,它像IE一样请求了所有的地址,不过在开发者工具界面上的显示与IE略有不同。

3)根据上面的测试,我想既然IE是陆续请求所有的src赋值,那么如果将img标签的src属性从html中去除掉,是否就不会请求“空地址”了?于是我将代码改成了:

<img id="image" onerror="this.onerror='';console.log('none');this.style.display='none'">

然后再进行测试,发现IE不再触发img的error事件,可以解决图片不显示的问题。

之后,我又测试了将src赋值为“javascript:;”,发现也不会在IE下触发img的error事件,其它部分浏览器(如Safari)虽然控制台可能会报错,但并不影响页面功能。

4)虽然本次实验是因为onerror而起,但就功能而言,其实用onload事件会更加容易实现和理解(各个浏览器表现一致)。只是最初入门前端时见到的是onerror这样的错误处理方法,往后就优先想到它,而没再往其它方向考虑。

使用onload的代码为:

/* 初始将图片隐藏 */
img{display:none;}
<!-- img标签有无src均可 -->
<img id="image" onload="this.style.display='block'">

附:最早见过的印象深刻的onerror用法

<img src=”main.png” onerror=” this.onerror=''; this.src=’default.png’”>
3、事后总结

解决问题的办法有两个:

1)将img标签的src属性不写或者写成正确但无意义的值(如src="javascript:;")。

<img id="image" onerror="this.onerror=''; this.style.display='none'">
<img src="javascript:;" id="image" onerror="this.onerror=''; this.style.display='none'">

2)使用onload代替onerror事件实现上文所述的功能。

<img id="image" onload="this.style.display='block'">
6人推荐
随时随地看视频
慕课网APP