圖片預加載,懶加載

1. 使用jQuery圖片預加載(延遲加載)插件Lazy Load

Lazy Load也叫惰性加載,延遲加載,顧名思義,就是在圖片未到達可視區域時,不加載圖片,咱們經常在不少的優秀網站上看到相似的例子,例如迅雷、土豆、優酷等,因爲一個網頁的圖片很是多,一次性加載增長服務器壓力,並且用戶未必會拉到底部,浪費用戶流量,Lazy Load採用按需加載,更快的加載速度從而達到優化網頁的目的。javascript

使用方法:css

  • 加載jQuery, 並在html代碼的底部包含進來

    <script src="jquery.js" type="text/javascript"></script>
    <script src="jquery.lazyload.js" type="text/javascript"></script>
  • 設置圖片的佔位符爲data-original, 給圖片一個特別的標籤, 像這樣設置圖片

    <img class="lazy" data-original="img/example.jpg" width="640" height="480">
    1
    2
    3
    $( function (){
         $( "img.lazy" ).lazyload();
    });

    注意:你必須給圖片設置一個height和width,或者在CSS中定義,不然可能會影響到圖片的顯示。html

  • 插件選項

    圖片預先加載距離:threshold,經過設置這個值,在圖片未出如今可視區域的頂部距離這個值時加載。默認爲0,下面爲設置threshold爲200表示在圖片距離可視區域還有200像素時加載。
    $("img.lazy").lazyload({
        threshold :200
    });

    事件綁定加載的方式:event,你可使用jQuery的事件,例如「click」、「mouseover」,或者你也能夠自定義事件,默認等待用戶滾動,圖片出如今可視區域。下面是使用click:前端

    1
    $( "img.lazy" ).lazyload({event: "click" });

    顯示效果:effect,默認使用show(),你可使用fadeIn(逐漸出現)方式,代碼以下:java

    1
    2
    3
    $( "img.lazy" ).lazyload({
         effect : "fadeIn"
    });

    對於禁用javascript的瀏覽器則要加上noscript內容:jquery

    <img class="lazy" data-original="img/example.jpg" width="640" heigh="480">
    <noscript><img src="img/example.jpg" alt="jQuery圖片預加載(延遲加載)插件Lazy Load" width="640" heigh="480"></noscript>

    圖片限定在某個容器內:container,你能夠經過限定某個容器內容的圖片纔會生效,代碼以下:css3

    #container {
        height:600px;
        overflow: scroll;
    }
    $("img.lazy").lazyload({
         container: $("#container")
    });  

  原文連接: jQuery圖片預加載(延遲加載)插件Lazy Loadweb

2. JS實現圖片預加載

  在瀏覽器渲染圖片的時候, 它得到圖片的一片區域的時候, 就已經爲這張圖片預留了一片空白的區域來填充圖片, 這就是預加載得到圖片尺寸最原始的使用方法.ajax

  有時候會加載一些在當前頁面沒有用到的圖片,是爲了提早加載到緩存裏,這樣後面的頁面就能夠直接從緩存讀取了。數組

  加載大圖的時候,咱們能夠先顯示模糊的縮略圖,等到大圖加載完了,再把縮略圖替換掉,這樣填補了圖片加載期間的空白時間。

  image也有onload和onerror事件,分別是加載完後和加載失敗時執行。

  Image對象是專門用於處理圖片加載的,就至關於內存中的img標籤。

  圖片預加載案例:鼠標移入一張圖片時,換成另外一張圖片,移出時換回原來的圖片。正常作法是,鼠標移入的時候,改變圖片的src,但這時就要去加載圖片了,會等待一段時間,這樣體驗很差。預加載的作法是,在頁面加載完,鼠標移入以前就經過Image對象把圖片加載進緩存了,這樣鼠標移入的時候直接從緩存裏讀取了,速度很快。

  • 圖片預加載:

    1
    2
    3
    4
    if (document.images){
         var  img =  new  Image();
         img.src =  "img/example.jpg" ;
    }

 

  • 封裝成一個預加載圖片的函數

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //實現圖片的預加載
    function  preloadImg(srcArr){
         if (srcArr  instanceof  Array){
             for ( var  i=0; i<srcArr.length; i++){
                 var  oImg =  new  Image();
                 oImg.src = srcArr[i];
             }
         }
    }
     
    //預加載圖片
    preloadImg([ 'image/example.jpg' ]);   //參數是一個url數組  
  • 使用一個回調函數來得到圖片的屬性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function  getPreloadImgAttr(url,callback){
         var  oImg =  new  Image();  //建立一個Image對象,實現圖片的預加載
         oImg.src = url;       // 看下一節,其實應當先進行onload的綁定,再賦值給src
         if (oImg.complete){
             //若是圖片已經存在於瀏覽器緩存,直接調用回調函數
             callback.call(oImg);
             return //直接返回,再也不處理onload事件
         }
         oImg.onload =  function (){
             //圖片下載完畢時異步調用callback函數
             callback.call(oImg);   
         };
    }
    getPreloadImgAttr( 'image/example.jpg' , function (){
         console.log( this .width,  this .height);
    });  
  • 關於預加載圖片的改進

    網上看到一篇博客關於圖片的預加載,你所不知道的, 其中指出以上通用的方法存在一些問題:
    • 建立了一個臨時匿名函數來做爲圖片的onload事件處理函數,造成了閉包。

      相信你們都看到過ie下的內存泄漏模式的文章,其中有一個模式就是循環引用,而閉包就有保存外部運行環境的能力(依賴於做用域鏈的實現),因此img.onload這個函數內部又保存了對img的引用,這樣就造成了循環引用,致使內存泄漏。(這種模式的內存泄漏只存在低版本的ie6中,打過補丁的ie6以及高版本的ie都解決了循環引用致使的內存泄漏問題)。

    • 只考慮了靜態圖片的加載,忽略了gif等動態圖片,這些動態圖片可能會屢次觸發onload。
    •   改進方法:
      1
      2
      3
      4
      5
      6
      7
      8
      function  loadImage(url, callback) {    
           var  img =  new  Image();  //建立一個Image對象,實現圖片的預下載    
           img.onload =  function (){
               img.onload =  null ;
               callback(img);
           }
           img.src = url;
      }

        這樣內存泄漏,動態圖片的加載問題都獲得瞭解決,並且也以統一的方式,實現了callback的調用。
      關於這個方法, 有個疑問是緩存的問題, 在原文裏也給出了一些解釋

      通過對多個瀏覽器版本的測試,發現ie、opera下,當圖片加載過一次之後,若是再有對該圖片的請求時,因爲瀏覽器已經緩存住這張圖
      片了,不會再發起一次新的請求,而是直接從緩存中加載過來。對於 firefox和safari,它們試圖使這兩種加載方式對用戶透明,一樣
      會引發圖片的onload事件,而ie和opera則忽略了這種同一性,不會引發圖片的onload事件,所以上邊的代碼在它們裏邊不能得以實
      現效果。

      但總體來說,仍然應該先進行onload事件的綁定, 再賦值src

  參考:[前端] 圖片預加載及獲取屬性  關於圖片的預加載,你所不知道的

3. 用CSS實現圖片的預加載

  這個概念就是寫一個CSS樣式設置一批背景圖片,而後將其隱藏,這樣你就看不到那些圖片了。那些背景圖片就是你想預載的圖片。

1
2
3
#preload -01  background url (http://domain.tld/image -01 .png)  no-repeat  -9999px  -9999px ; } 
#preload -02  background url (http://domain.tld/image -02 .png)  no-repeat  -9999px  -9999px ; } 
#preload -03  background url (http://domain.tld/image -03 .png)  no-repeat  -9999px  -9999px ; }

  這裏爲了隱藏這些圖片, 使用了位置設置爲極大的負值的方法. 還能夠直接設置 { width: 0; height: 0; display: none};

  該方法雖然高效,但仍有改進餘地。使用該法加載的圖片會同頁面的其餘內容一塊兒加載,增長了頁面的總體加載時間。爲了解決這個問題,咱們增長了一些JavaScript代碼,來推遲預加載的時間,直到頁面加載完畢。代碼以下:

複製代碼
// better image preloading @ <a href="http://perishablepress.com/press/2009/12/28/3-ways-preload-images-css-javascript-ajax/">http://perishablepress.com/press/2009/12/28/3-ways-preload-images-css-javascript-ajax/</a>  
function preloader() {  
    if (document.getElementById) {  
        document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";  
        document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";  
        document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";  
    }  
}  
function addLoadEvent(func) {  
    var oldonload = window.onload;  
    if (typeof window.onload != 'function') {  
        window.onload = func;  
    } else {  
        window.onload = function() {  
            if (oldonload) {  
                oldonload();  
            }  
            func();  
        }  
    }  
}  
addLoadEvent(preloader);
複製代碼

  在該腳本的第一部分,咱們獲取使用類選擇器的元素,併爲其設置了background屬性,以預加載不一樣的圖片。

  該腳本的第二部分,咱們使用addLoadEvent()函數來延遲preloader()函數的加載時間,直到頁面加載完畢。

  若是JavaScript沒法在用戶的瀏覽器中正常運行,會發生什麼?很簡單,圖片不會被預加載,當頁面調用圖片時,正常顯示便可。

  參考: 純CSS圖片預加載  Javascript圖片預加載詳解

4. 使用Ajax實現預加載

  該方法利用DOM,不只僅預加載圖片,還會預加載CSS、JavaScript等相關的東西。使用Ajax,比直接使用JavaScript,優越之處在於JavaScript和CSS的加載不會影響到當前頁面。該方法簡潔、高效。

複製代碼
window.onload = function() {  
    setTimeout(function() {  
        // XHR to request a JS and a CSS  
        var xhr = new XMLHttpRequest();  
        xhr.open('GET', 'http://domain.tld/preload.js');  
        xhr.send('');  
        xhr = new XMLHttpRequest();  
        xhr.open('GET', 'http://domain.tld/preload.css');  
        xhr.send('');  
        // preload image  
        new Image().src = "http://domain.tld/preload.png";  
    }, 1000);  
};  
複製代碼

  上面代碼預加載了「preload.js」、「preload.css」和「preload.png」。1000毫秒的超時是爲了防止腳本掛起,而致使正常頁面出現功能問題。

  與之相比, 若是用js的話, 要實現以上加載過程則會應用到頁面上. 實現以下

複製代碼
window.onload = function() {  
  
    setTimeout(function() {  
  
        // reference to <head>  
        var head = document.getElementsByTagName('head')[0];  
  
        // a new CSS  
        var css = document.createElement('link');  
        css.type = "text/css";  
        css.rel  = "stylesheet";  
        css.href = "http://domain.tld/preload.css";  
  
        // a new JS  
        var js  = document.createElement("script");  
        js.type = "text/javascript";  
        js.src  = "http://domain.tld/preload.js";  
  
        // preload JS and CSS  
        head.appendChild(css);  
        head.appendChild(js);  
  
        // preload image  
        new Image().src = "http://domain.tld/preload.png";  
  
    }, 1000);  
  
};
複製代碼

 

  這裏,咱們經過DOM建立三個元素來實現三個文件的預加載。正如上面提到的那樣,使用Ajax,加載文件不會應用到加載頁面上。從這點上看,Ajax方法優越於JavaScript。

  參考: Javascript圖片預加載詳解

 
分類:  前端
標籤:  前端圖片預加載
相關文章
相關標籤/搜索