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下圖片無法顯示,但從開發者工具中可以看到圖片是正確請求了。其它瀏覽器(Chrome、Opera、FireFox、Safari)表現符合預期。
之后我對IE做了一些測試,測試內容如下:
1)當不傳參數時,img的error事件會被觸發,控制臺輸出none,這一點跟其它瀏覽器一致;
2)當傳參時,其它瀏覽器均不觸發error事件,只有IE會觸發;
按照瀏覽器的加載原則,圖片會在其它所有代碼之后加載,所以頁面先獲取到了圖片地址參數并更新到了img標簽上,然后才去加載圖片。也就是說,當加載圖片時,圖片的地址已經是最終的那個傳參了,理論上是不應該觸發error事件的。
IE這個行為比較奇怪。經過一番琢磨后,我猜想IE是不是在自上而下讀到img標簽處時,雖然沒立即加載圖片,但是卻把圖片的地址添加到了后續的計劃任務中,就好像打印機那樣,然后在其它代碼加載完之后陸續請求了這些地址(就像是請求了一個地址數組[“”,”1.jpg”])。為了驗證這一猜想,我做了如下的一番測試:
① 編寫了一個新的頁面,功能是在初始化時,通過循環多次修改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)根據上面的測試,我將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;}
// 此處有無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'">