您無法控制事情的時機,以這種方式可靠地按照您嘗試這樣做的方式進行工作。這裏的秩序的事情發生了:
- 瀏覽器獲取的HTML頁面
- 瀏覽器開始解析HTML
- 它找到一個
<img>
標籤,它觸發關閉加載src
URL的請求。
- 瀏覽器發現src URL無法加載,從而觸發
onerror
處理程序。
- 您的JavaScript運行並安裝
onerror
處理程序。
現在,步驟4和步驟5的順序完全與時間有關並且不受您的控制。有些情況可能會導致它按照這種順序發生,而4和5的某些情況則會發生逆轉。並且請記住,一旦您的頁面被加載一次,其中的一部分可能會被緩存,並且後續加載中的時序可能會有所不同。某些瀏覽器甚至可能緩存URL當前無法訪問的事實,並且如果它立即再次請求(從而生成立即的錯誤響應),則可能會避免再次嘗試它。
此外,當.src
屬性設置爲新值時,某些瀏覽器的行爲完全不正確。幾年前,我知道某些瀏覽器在更改.src
屬性並加載新映像時並未可靠地觸發onload
事件。對於onerror
處理程序也是如此。我的經驗是,他們可以可靠地爲第一次圖像加載工作,但我不確定他們在設置不同的.src
屬性時可靠地工作。
要設置一個不會錯過的錯誤處理程序,必須在.src
屬性被設置或解析之前使用它。這有兩種方法可以做到這一點。
- 將使用onerror處理程序的HTML本身,以便它是
<img>
標籤的一部分。
- 在您的HTML中沒有完全形成
<img>
標籤(例如,src或不在HTML中),然後用你的javascript,你可以添加onerror處理程序,然後創建圖像或適當地設置.src
。
關鍵是onerror
處理程序必須在以任何方式設置.src
屬性之前安裝。
解決方案#1是這樣的:實現的解決方案#2
<img src="xxx.jpg" onerror="setErrorImage(this)">
// this function must be in the global scope
function setErrorImage(img) {
// clear error handler so no chance of looping
img.onerror = function() {};
img.src = base_url() + 'assets/images/placeholder.jpg';
}
一種方法是這樣的:
<img data-src="xxx.jpg">
(function() {
function setErrorImage() {
this.removeEventListener("error", setErrorImage);
this.src = base_url() + 'assets/images/placeholder.jpg';
}
var imgElements = document.getElementsByTagName('img');
var img, url;
for (var i = 0; i < imgElements.length; i++) {
img = imgElements[i];
// now that onerror handler is in place, set the .src property
url = img.getAttribute("data-src")
if (!img.src && url) {
img.addEventListener("error", setErrorImage);
img.src = url;
}
}
})();
你也可以沒有<img>
標籤在HTML不惜一切創造所有這些動態通過JavaScript動態,確保在設置.src
屬性之前安裝了onerror處理程序,但這往往會使設計過程更復雜一些。對於選項#2,上述解決方案通常優先於完全以代碼形式創建圖像對象。
您正在使用'i',但它不是一個閉包變量,因此它將包含循環中的最後一個值。 – Barmar
我已經改變它傳遞對象'imgElements [i]',它仍然導致相同的功能。 –
其實,這不相關。你沒有在回調函數中使用'i'。我不明白你爲什麼把所有這些IIFE放在首位,他們只是讓代碼更加混亂。 – Barmar