天天看點

圖檔加載失敗的前端解決方案

圖檔加載失敗的前端解決方案

在實際項目中,不可避免的會遇到在頁面中加載大量圖檔,但可能由于網絡問題,或者圖檔檔案缺失等問題,導緻圖檔不能正常展示,并且在不同浏覽器處理錯誤圖檔是不一樣的,有的幹脆就顯示差号,例如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>