2017-03-24 263 views
5

我正在建立一個循環遍歷3個不同背景的頁面,每750ms更改一次。爲了做到這一點,我添加了一個類與相關的背景圖片,改變與JS。對於第一個循環,它們會閃爍,因爲圖像必須加載,所以它不會立即顯示。因此,是否有任何方法可用於預加載圖像?預加載背景圖像

CSS:

&.backgrounds{ 
    background-position: center bottom; 
    background-repeat: no-repeat; 
    background-size: 130%; 

    &.freddy{ 
     background-image: url(/img/illustrations/snapchat/snapchat_holding_page_freddy.jpg); 
    } 

    &.irene{ 
     background-image: url(/img/illustrations/snapchat/snapchat_holding_page_irene.jpg); 
    } 

    &.joe{ 
     background-image: url(/img/illustrations/snapchat/snapchat_holding_page_joe.jpg); 
    } 
} 

JS:

setInterval(function() { 
    if ($('.backgrounds').hasClass('freddy')){ 
     $('.backgrounds').removeClass('freddy').addClass('irene'); 

    } else if ($('.backgrounds').hasClass('irene')){ 
     $('.backgrounds').removeClass('irene').addClass('joe'); 

    } else if ($('.backgrounds').hasClass('joe')){ 
     $('.backgrounds').removeClass('joe').addClass('freddy'); 

    } 
}, 750); 

回答

4

我會做這樣的事情。 loadImages返回一個Promise,一旦加載所有圖像,該Promise就會解析。連接到它的.then調用cycleImages,它啓動間隔。由於您需要JS中的URL來進行預加載,而不是類切換,所以我直接操縱background-image,這樣您就可以從CSS中刪除圖像URL並保存少量冗餘字節。這也使得在未來擴展圖像列表變得更容易,您只需要將一個項目添加到圖像數組中,而不是維護複雜的if語句。

function loadImages (images) { 
 
    // each image will be loaded by this function. 
 
    // it returns a Promise that will resolve once 
 
    // the image has finished loading 
 
    let loader = function (src) { 
 
    return new Promise(function (resolve, reject) { 
 
     let img = new Image(); 
 
     img.onload = function() { 
 
     // resolve the promise with our url so it is 
 
     // returned in the result of Promise.all 
 
     resolve(src); 
 
     }; 
 
     img.onerror = function (err) { 
 
     reject(err); 
 
     }; 
 
     img.src = src; 
 
    }); 
 
    }; 
 

 
    // create an image loader for each url 
 
    let loaders = []; 
 
    images.forEach(function (image) { 
 
    loaders.push(loader(image)); 
 
    }); 
 

 
    // Promise.all will return a promise that will resolve once all of of our 
 
    // image loader promises resolve 
 
    return Promise.all(loaders); 
 
} 
 

 

 
// the images we are going to display 
 
let myImages = [ 
 
    'http://www.gifpng.com/400x200', 
 
    'http://www.gifpng.com/400x200/ffffff/000000', 
 
    'http://www.gifpng.com/400x200/000000/ffffff' 
 
]; 
 

 
// $(document).ready(fn) is deprecated, 
 
// use the $(fn) form instead 
 
$(function() { 
 

 
    // after the images are loaded this will be called with an array of the loaded images 
 
    function cycleImages (images) { 
 
    let index = 0; 
 
    setInterval(function() { 
 
     // since we need an array of the image names to preload them anyway, 
 
     // just load them via JS instead of class switching so you can cut them 
 
     // out of the CSS and save some space by not being redundant 
 
     $('#backgrounds').css('backgroundImage', 'url("' + images[index] + '")'); 
 
     // increment, roll over to 0 if at length after increment 
 
     index = (index + 1) % images.length; 
 
    }, 750); 
 
    } 
 

 

 
    // load the images and start cycling through them after they are loaded 
 
    loadImages(myImages).then(cycleImages).catch(function (err) { 
 
    console.error(err); 
 
    }); 
 
});
#backgrounds { 
 
    height: 200px; 
 
    width: 400px; 
 
    border: 1px solid #000; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="backgrounds"></div>

編輯:Just a student的意見考慮進去,這裏是一個版本,一旦它被加載,將只切換圖像,但這樣做是正確的路程,如果它被加載。它也會跳過加載失敗的圖像。由於cycleImages不再通過.then調用,因此我也對其進行了更改,以便它接受一個目標元素(作爲jQuery對象)以及一組圖像承諾。這樣,如果您願意,您可以在具有不同圖像集的頁面上的多個位置輕鬆使用此功能。

function loadImages (images) { 
 
    // each image will be loaded by this function. 
 
    // it returns a Promise that will resolve once 
 
    // the image has finished loading 
 
    let loader = function (src) { 
 
    return new Promise(function (resolve, reject) { 
 
     let img = new Image(); 
 
     img.onload = function() { 
 
     // resolve the promise with our url 
 
     resolve(src); 
 
     }; 
 
     img.onerror = function (err) { 
 
     reject(err); 
 
     }; 
 
     img.src = src; 
 
    }); 
 
    }; 
 

 
    // return an array of image-loading promises 
 
    return images.map(function (image) { 
 
    return loader(image); 
 
    }); 
 
} 
 

 

 
// the images we are going to display 
 
let myImages = [ 
 
    'http://www.gifpng.com/400x200', 
 
    'http://www.invalid-domain-name.foo/this-url-certainly-does-not-exist.jpg', 
 
    'http://www.gifpng.com/400x200/ffffff/000000', 
 
    'http://www.gifpng.com/400x200/000000/ffffff' 
 
]; 
 

 
// $(document).ready(fn) is deprecated, 
 
// use the $(fn) form instead 
 
$(function() { 
 

 
    // this receives an array of the promises for each image 
 
    function cycleImages ($target, images) { 
 
    let index = 0, 
 
     interval = 750; // how many ms to wait before attempting to switch images 
 

 
    function nextImage() { 
 
     // p is the promise for the current image 
 
     let p = images[index], 
 
     next = function (wait) { 
 
      // increment our counter and wait to display the next one 
 
      index = (index + 1) % images.length; 
 
      setTimeout(nextImage, wait); 
 
     }; 
 

 
     // wait for this image to load or fail to load 
 
     p.then(function (src) { 
 
     // it loaded, display it 
 
     $target.css('backgroundImage', 'url("' + src + '")'); 
 
     next(interval); 
 
     }).catch(function (err) { 
 
     // this one failed to load, skip it 
 
     next(0); 
 
     }); 
 

 
    } 
 

 
    // start cycling 
 
    nextImage(); 
 
    } 
 

 

 
    // load the images and start cycling through them as they are loaded 
 
    cycleImages($('#backgrounds'), loadImages(myImages)); 
 
});
#backgrounds { 
 
    height: 200px; 
 
    width: 400px; 
 
    border: 1px solid #000; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="backgrounds"></div>

而不是硬編碼的圖像之間的間隔變化,你也可以把它傳遞作爲參數。但是,在那一點上,我會重構它以使用配置對象來傳遞除圖像承諾數組之外的所有內容:cycleImages(myImages, {target: $('#backgrounds'), interval: 1000});

+0

一方面,您可能想考慮將間隔更改爲每隔幾秒而不是每隔750毫秒。大多數人會因爲這種快速閃爍的事情而感到非常煩惱。作爲一名注意力不集中的人,我可以告訴你,頁面上快速閃爍的內容使人們很難專注於閱讀頁面上的任何內容;這太讓人分心了。即使沒有ADD的人也會因分心而受損。 –

+0

很好的答案!一個建議:目前,所有圖像都在顯示第一個圖像之前加載。它可能是一個很好的替代解決方案,只在需要時才加載映像,並簡單地延遲交換機,直到Promise解決。這意味着對於第一個循環,您還不能使用間隔,而是需要確保(a)750毫秒(或任何您設置的)已經通過,並且(b)下一個圖像被加載。事實上,Promise也可以很好地完成。 –

+0

哦,現在的解決方案的另一個缺點是即使只有一個不能被訪問,也不會顯示背景圖像。 –

0

有趣的想法。

你能潛在地在後臺加載它們這麼喜歡:

<div class="hidden-images"> 
    <img src="img1.jpg" /> 
    <img src="img2.jpg" /> 
    <img src="img3.jpg" /> 
</div> 

然後在CSS

.hidden-images { 
    position: relative; 
    z-index: 1; 
} 

然後在任何你排序主容器DIV的是,一巴掌就以下?

.main-container { 
    position: relative; 
    z-index: 2; // Or higher, whatever is needed 
} 
1

您可以使用javascript加載它們。如:

(new Image()).src = url1; 
(new Image()).src = url2; 
(new Image()).src = url3; 

更改「url1」,「url2」,「url3」與你自己的圖像網址。瀏覽器將加載圖像,但它們不會在任何地方可見。

0

你也可以用不同的html和css結構來做到這一點。

HTML

<div class="backgrounds"> 
    <div class="background freddy"></div> 
</div> 

CSS

.backgrounds{ 
    background-color: transparent; 
    background-position: center bottom; 
    background-repeat: no-repeat; 
    background-size: 130%; 
    height: 250px; 
    width; 100%; 
} 

.backgrounds .freddy{ 
     height: 100%; 
     width: 100%; 
     background-image: url('http://adrianweb.net/includes/images/hero.jpg'); 
    } 

.backgrounds .irene{ 
     height: 100%; 
     width: 100%; 
     background-image: url('http://adrianweb.net/includes/images/projects-blur.png'); 
    } 

.backgrounds .joe{ 
     height: 100%; 
     width: 100%; 
     background-image: url('http://adrianweb.net/includes/images/contacts-blur.png'); 
    } 

JS

$(document).ready(function(){ 
setInterval(function() { 
    if ($('.background').hasClass('freddy')){ 
     $('.background').removeClass('freddy').addClass('irene'); 

    } else if ($('.background').hasClass('irene')){ 
     $('.background').removeClass('irene').addClass('joe'); 

    } else if ($('.background').hasClass('joe')){ 
     $('.background').removeClass('joe').addClass('freddy'); 

    } 
}, 750); 
}); 

也許你可以添加過渡/動畫,使它看起來淡入和淡出。

樣品下面codepen:

http://codepen.io/adrianrios/pen/yMEpEv