
在實際項目中,不可避免的會遇到在頁面中加載大量圖檔,但可能由于網絡問題,或者圖檔檔案缺失等問題,導緻圖檔不能正常展示,并且在不同浏覽器處理錯誤圖檔是不一樣的,有的幹脆就顯示差号,例如IE,有的顯示一張破碎的圖檔,有的則是給一張高度比較大的預設圖,例如PC端的火狐,IOS中Safari,還有安卓中的UC浏覽器。
這樣在手機中就會導緻左右兩側圖檔高度不一緻!
我們希望有一種降級處理的方式,可以在圖檔加載失敗後顯示一張我們預先設定好的預設圖檔。
解決方案
由于圖檔加載失敗後,會抛出一個 error 事件,是以我們隻需要判斷當圖檔加載失敗的時候給一個預設圖就可以了,不讓浏覽器使用其自帶的預設圖。比如:
<img src="//fly63.com/img.png" onerror="this.src = '//fly63.com/default.png'">
但是這樣呢也會存在一些問題,比如:
1.我們需要手動的向 img 标簽中添加内聯事件,在實際開發過程中,很難保證每張圖檔都不漏寫。
2.因為圖檔加載失敗進入預設圖,那麼預設圖再加載失敗怎麼辦呢?
優化方案一:
我們可以通過在全局監聽的方式,來對異常圖檔做降級處理,這樣不用在每個img标簽中不用onerror事件。
監聽圖檔自身的 error 事件,實際上在事件流中是處于目标階段。對于 img 的 error 事件來說,是無法冒泡的,但是是可以捕獲的,我們的實作如下:
window.addEventListener('error',function(e){
//目前異常是由圖檔加載異常引起的
if( e.target.tagName.toUpperCase() === 'IMG' ){
e.target.src = '//fly63.com/default.jpg';
}
},true)
最後,我們在思考一個問題,當網絡出現異常的時候,必然會出現什麼網絡圖檔都無法加載的情況,這樣就會導緻我們監聽的 error 事件。
被無限觸發,是以我們可以設定一個計數器,當達到期望的錯誤次數時停止對圖檔賦予預設圖檔的操作,改為提供一個Base64的圖檔。
實作起來也很簡單,如下:
window.addEventListener('error',function(e){
let target = e.target, // 目前dom節點
tagName = target.tagName,
count = Number(target.dataset.count ) || 0, // 以失敗的次數,預設為0
max= 3; // 總失敗次數,此時設定為3
// 目前異常是由圖檔加載異常引起的
if( tagName.toUpperCase() === 'IMG' ){
if(count >= max){
target.src = 'data:image/jpeg;base64*******';//base64圖檔字元串
}else{
target.dataset.count = count + 1;
target.src = '//xxx/default.jpg';
}
}
},true)
優化方案二:
如果我們不需要全局監聽error事件,仍然想用onerror事件,如何保證不進入死循環呢?代碼如下:
<img src="//fly63.com/img.png" onerror="nofind()"/>
<script type="text/JavaScript">
function nofind(){
var img=event.srcElement || event.target ; //擷取img對象,火狐是event.target ,IE及谷歌其他是event.srcElement
img.src="//fly63.com/default.png";
img.onerror=null;
}
</script>