簡體   English   中英

Javascript - 在所有圖像加載后執行

[英]Javascript - execute after all images have loaded

看了別人的問題我想

window.onload=...

會回答我的問題。 我試過這個但是它在頁面加載時立即執行代碼(而不是在圖像加載之后)。

如果它有任何區別,圖像來自 CDN 並且不是相對的。

有人知道解決方案嗎? (我沒有使用 jQuery)

想要單線?

Promise.all(Array.from(document.images).filter(img => !img.complete).map(img => new Promise(resolve => { img.onload = img.onerror = resolve; }))).then(() => {
    console.log('images finished loading');
});

非常向后兼容,甚至可以在 Firefox 52 和 Chrome 49(Windows XP 時代)中使用。 不過在 IE11 中沒有。

如果您想縮小圖像列表,請將document.images替換為document.querySelectorAll(...)

為了簡潔起見,它使用onloadonerror 如果img元素的這些處理程序也在別處設置(不太可能,但無論如何),這可能會與頁面上的其他代碼沖突。 如果您不確定您的頁面沒有使用它們並希望安全,請替換部分img.onload = img.onerror = resolve; 有一個更長的: img.addEventListener('load', resolve); img.addEventListener('error', resolve); img.addEventListener('load', resolve); img.addEventListener('error', resolve); .

它也不會測試是否所有圖像都已成功加載(沒有損壞的圖像)。 如果你需要這個,這里有一些更高級的代碼:

Promise.all(Array.from(document.images).map(img => {
    if (img.complete)
        return Promise.resolve(img.naturalHeight !== 0);
    return new Promise(resolve => {
        img.addEventListener('load', () => resolve(true));
        img.addEventListener('error', () => resolve(false));
    });
})).then(results => {
    if (results.every(res => res))
        console.log('all images loaded successfully');
    else
        console.log('some images failed to load, all finished loading');
});

它會一直等到所有圖像都加載完畢或加載失敗。

如果你想盡早失敗,第一張損壞的圖像:

Promise.all(Array.from(document.images).map(img => {
    if (img.complete)
        if (img.naturalHeight !== 0)
            return Promise.resolve();
        else
            return Promise.reject(img);
    return new Promise((resolve, reject) => {
        img.addEventListener('load', resolve);
        img.addEventListener('error', () => reject(img));
    });
})).then(() => {
    console.log('all images loaded successfully');
}, badImg => {
    console.log('some image failed to load, others may still be loading');
    console.log('first broken image:', badImg);
});

兩個最新的代碼塊使用naturalHeight來檢測已加載圖像中的損壞圖像。 這種方法通常有效,但有一些缺點:據說當圖像 URL 通過 CSS content屬性設置時以及圖像是未指定尺寸的 SVG 時無效。 如果是這種情況,您將不得不重構代碼,以便在圖像開始加載之前設置事件處理程序。 這可以通過在 HTML 中指定onloadonerror或通過在 JavaScript 中創建img元素來完成。 另一種方法是在 HTML 中將src設置為data-src並在附加處理程序后執行img.src = img.dataset.src

這是現代瀏覽器的快速破解:

var imgs = document.images,
    len = imgs.length,
    counter = 0;

[].forEach.call( imgs, function( img ) {
    if(img.complete)
      incrementCounter();
    else
      img.addEventListener( 'load', incrementCounter, false );
} );

function incrementCounter() {
    counter++;
    if ( counter === len ) {
        console.log( 'All images loaded!' );
    }
}

加載所有圖像后,您的控制台將顯示“所有圖像已加載”。

這段代碼的作用:

  • 從文檔中加載變量中的所有圖像
  • 循環瀏覽這些圖像
  • 在每個圖像上為“load”事件添加一個偵聽器以運行incrementCounter函數
  • incrementCounter將遞增計數器
  • 如果計數器已達到圖像的長度,則表示它們已全部加載

以跨瀏覽器的方式使用這段代碼並不難,只是像這樣更干凈。

Promise Pattern 將以最好的方式解決這個問題我已經提到 when.js 一個開源庫來解決所有圖像加載的問題

function loadImage (src) {
    var deferred = when.defer(),
        img = document.createElement('img');
    img.onload = function () { 
        deferred.resolve(img); 
    };
    img.onerror = function () { 
        deferred.reject(new Error('Image not found: ' + src));
    };
    img.src = src;

    // Return only the promise, so that the caller cannot
    // resolve, reject, or otherwise muck with the original deferred.
    return deferred.promise;
}

function loadImages(srcs) {
    // srcs = array of image src urls

    // Array to hold deferred for each image being loaded
    var deferreds = [];

    // Call loadImage for each src, and push the returned deferred
    // onto the deferreds array
    for(var i = 0, len = srcs.length; i < len; i++) {
        deferreds.push(loadImage(srcs[i]));

        // NOTE: We could push only the promise, but since this array never
        // leaves the loadImages function, it's ok to push the whole
        // deferred.  No one can gain access to them.
        // However, if this array were exposed (e.g. via return value),
        // it would be better to push only the promise.
    }

    // Return a new promise that will resolve only when all the
    // promises in deferreds have resolved.
    // NOTE: when.all returns only a promise, not a deferred, so
    // this is safe to expose to the caller.
    return when.all(deferreds);
}

loadImages(imageSrcArray).then(
    function gotEm(imageArray) {
        doFancyStuffWithImages(imageArray);
        return imageArray.length;
    },
    function doh(err) {
        handleError(err);
    }
).then(
    function shout (count) {
        // This will happen after gotEm() and count is the value
        // returned by gotEm()
        alert('see my new ' + count + ' images?');
    }
);

使用window.onload將不起作用,因為它會在頁面加載后觸發,但是圖像不包含在此加載的定義中。

對此的一般解決方案是ImagesLoaded jQuery 插件。

如果您根本不想使用 jQuery,您至少可以嘗試將此插件轉換為純 Javascript。 在 93 行重要的代碼和良好的注釋下,完成它應該不是一項艱巨的任務。

您可以在圖像上設置 onload 事件,該事件可以回調執行處理的函數...關於如何處理所有圖像是否已加載,我不確定以下任何機制是否有效:

有一個函數可以計算調用 onload 的圖像數量,如果這等於頁面上的圖像總數,則進行必要的處理。

游戲開始有些晚,但是我發現以下方法最簡單:

function waitForImages () {
  let isLoading = true

  while (isLoading) {
    const loading = [].slice.call(document.images).filter(img => img.complete !== true)
    if (!loading.length > 0) {
      isLoading = true
      return
    }
  }
}

請注意,這是阻塞代碼(如果您嘗試確保將圖像加載到諸如phantomjs之類的文件中,則很有用)

 <title>Pre Loading...</title>
 </head>

 <style type="text/css" media="screen"> html, body{ margin:0;
 padding:0; overflow:auto; }
 #loading{ position:fixed; width:100%; height:100%; position:absolute; z-index:1; ackground:white url(loader.gif) no-repeat center; }**
 </style>

 <script> function loaded(){
 document.getElementById("loading").style.visibility = "hidden"; }
 </script>

 <body onload="loaded();"> <div id="loading"></div>

 <img id="img" src="avatar8.jpg" title="AVATAR" alt="Picture of Avatar
 movie" />


 </body>

我一直在尋找這樣的東西,如果您不介意使用 setInterval,那么這段代碼簡單明了。 就我而言,我可以使用 setInterval,因為它可能會運行 4-5 次。

const interval = setInterval(() => {
    const allImagesLoaded = [...document.querySelectorAll('img')]
      .map(x => x.complete)
      .indexOf(false) === -1;
    if (allImagesLoaded) {
      window.print();
      clearInterval(interval);
    }
  }, 500);

我正要建議 Baz1nga 說的同樣的話。

此外,另一種可能不是萬無一失但更易於維護的可能選擇是選擇最重要/最大的圖像並將 onload 事件附加到該圖像。 這樣做的好處是,如果您以后向頁面添加更多圖像,需要更改的代碼會更少。

這很好用:

$(function() {
 $(window).bind("load", function() {
    // code here
 });
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM