1、簡(jiǎn)介
現(xiàn)需在一個(gè)html頁面中顯示一張圖片,這張圖片的地址是通過GET方式從地址欄中傳入的。但是如果圖片損壞或傳參錯(cuò)誤,在部分瀏覽器下會(huì)出現(xiàn)破裂圖,所以當(dāng)遇到這種情況則將圖片隱藏掉。
地址示例:http://example.com/test.html?s=1.jpg
據(jù)此要求編寫的初始代碼如下(代碼中的兩個(gè)console用于后續(xù)的測(cè)試):
HTML
<img src="" id="image" onerror="this.onerror='';console.log('none');this.style.display='none'">
JS
var imgSrc=GetUrlParams().s||"";? ?// GetUrlParams是用來獲取url中的參數(shù)的,參數(shù)名為s
var img=document.getElementById("image");
if (imgSrc) {
????img.src=imgSrc+"?t="+Math.random();
????console.log('block');
????img.style.display='block';
}
2、問題
當(dāng)用上述代碼在各瀏覽器中進(jìn)行測(cè)試時(shí),發(fā)現(xiàn)在IE下圖片無法顯示,但從開發(fā)者工具中可以看到圖片是正確請(qǐng)求了。其它瀏覽器(Chrome、Opera、FireFox、Safari)表現(xiàn)符合預(yù)期。
之后我對(duì)IE做了一些測(cè)試,測(cè)試內(nèi)容如下:
1)當(dāng)不傳參數(shù)時(shí),img的error事件會(huì)被觸發(fā),控制臺(tái)輸出none,這一點(diǎn)跟其它瀏覽器一致;

2)當(dāng)傳參時(shí),其它瀏覽器均不觸發(fā)error事件,只有IE會(huì)觸發(fā);

按照瀏覽器的加載原則,圖片會(huì)在其它所有代碼之后加載,所以頁面先獲取到了圖片地址參數(shù)并更新到了img標(biāo)簽上,然后才去加載圖片。也就是說,當(dāng)加載圖片時(shí),圖片的地址已經(jīng)是最終的那個(gè)傳參了,理論上是不應(yīng)該觸發(fā)error事件的。
IE這個(gè)行為比較奇怪。經(jīng)過一番琢磨后,我猜想IE是不是在自上而下讀到img標(biāo)簽處時(shí),雖然沒立即加載圖片,但是卻把圖片的地址添加到了后續(xù)的計(jì)劃任務(wù)中,就好像打印機(jī)那樣,然后在其它代碼加載完之后陸續(xù)請(qǐng)求了這些地址(就像是請(qǐng)求了一個(gè)地址數(shù)組[“”,”1.jpg”])。為了驗(yàn)證這一猜想,我做了如下的一番測(cè)試:
① 編寫了一個(gè)新的頁面,功能是在初始化時(shí),通過循環(huán)多次修改img的src屬性,然后觀察IE是否會(huì)對(duì)所有賦值都發(fā)起請(qǐng)求。
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();}
測(cè)試后發(fā)現(xiàn),IE的確請(qǐng)求了數(shù)組中所有的地址,但在變更img的src的過程中,被廢棄的那些圖片地址都顯示掛起,應(yīng)該是被中斷掉了。

② 繼續(xù)觀察該測(cè)試頁面在其它瀏覽器下的反應(yīng),發(fā)現(xiàn)Chrome、FireFox、Opera均只請(qǐng)求了最后那張圖片的地址。

但是Safari的表現(xiàn)有點(diǎn)意外了,它像IE一樣請(qǐng)求了所有的地址,不過在開發(fā)者工具界面上的顯示與IE略有不同。

3)根據(jù)上面的測(cè)試,我將img標(biāo)簽的src屬性從html中去除掉,代碼成了:
<img id="image" onerror="this.onerror='';console.log('none');this.style.display='none'">
然后再進(jìn)行測(cè)試,發(fā)現(xiàn)IE不再觸發(fā)img的error事件,可以解決圖片不顯示的問題。?

之后,我又測(cè)試了將src賦值為“javascript:;”,發(fā)現(xiàn)也不會(huì)在IE下觸發(fā)img的error事件,其它部分瀏覽器(如Safari)雖然控制臺(tái)可能會(huì)報(bào)錯(cuò),但并不影響頁面功能。
4)雖然本次實(shí)驗(yàn)是因?yàn)閛nerror而起,但就功能而言,其實(shí)用onload事件會(huì)更加容易實(shí)現(xiàn)和理解(各個(gè)瀏覽器表現(xiàn)一致)。只是最初入門前端時(shí)見到的是onerror這樣的錯(cuò)誤處理方法,往后就優(yōu)先想到它,而沒再往其它方向考慮。
使用onload的代碼為:
// 初始將圖片隱藏
img{display:none;}
// 此處有無src均可
<img id="image" onload="this.style.display='block'">
附:最早見過的印象深刻的onerror用法
<img src=”main.png” onerror=” this.onerror=''; this.src=’default.png’”>
3、結(jié)論
解決問題的辦法有兩個(gè):
1)將img標(biāo)簽的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事件實(shí)現(xiàn)上文所述的功能。
<img id="image" onload="this.style.display='block'">