1. 程式人生 > >大圖片載入、懶載入實現原理(滾動載入圖片)

大圖片載入、懶載入實現原理(滾動載入圖片)

大圖片載入從模糊到清晰:

解決辦法是等圖片完全載入好了再顯示出來,具體點來說:

建立image物件,將要載入的圖片URL賦值給image物件的src,監聽image物件的onload事件,在事件回撥函式內修改img元素的src,也可以設定圖片元素的position將元素偏移非可視區直接載入,圖片載入完後丟回可視區

<!DOCTYPE html>
<html>
<head>
    <title>大圖片載入從模糊到清晰</title>
    <style type="text/css">
    .content{
        position: relative;
    }
    .thumbnails{
        width: 300px;
        position: absolute;
        left: 0;
        top: 0;
        z-index: 1;
        filter: blur(4px);
        transition: all 0.7s;
    }
    .complete{
        filter: blur(0);
    }
    </style>
</head>
<body>
    <h3>大圖片載入從模糊到清晰</h3>
    <div class="content">
        <img class="thumbnails" src="data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTY3NjUwN0QyQjRBMTFFN0FCMjJERjYzMkVDMTQzRUEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTY3NjUwN0UyQjRBMTFFN0FCMjJERjYzMkVDMTQzRUEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5Njc2NTA3QjJCNEExMUU3QUIyMkRGNjMyRUMxNDNFQSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5Njc2NTA3QzJCNEExMUU3QUIyMkRGNjMyRUMxNDNFQSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/uAA5BZG9iZQBkwAAAAAH/2wCEAAYEBAQFBAYFBQYJBgUGCQsI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">
    </div>
    <script type="text/javascript">
        var ele = document.querySelector('.thumbnails');
        // 為了看到效果加個延時
        setTimeout(function(){
            // 若圖片URL失效請自行替換
            var imgUrl = 'http://img8.zol.com.cn/bbs/upload/10569/10568721.jpg';
            var imgObject = new Image();

            imgObject.src = imgUrl;
            imgObject.onload = function(){
                ele.src = imgUrl;
                ele.setAttribute('class', 'thumbnails complete');
            }
        }, 1000)
    </script>
</body>
</html>

縮圖比較難看,為了有更好的使用者體驗,可以給縮圖加個高斯模糊filter: blur(4px),圖片載入完畢修改img src屬性後,再將高斯模糊漸漸過渡到filter: blur(0),圖片就清晰了

demo中,縮圖用base64編碼表示,這是節省頻寬的一種方式,如果有多個縮圖,可用一個http請求以字串按某個分隔符的形式返回,前端解析後使用,減少了http請求,圖片載入優化還有更多方式,包括用css繪製簡單的樣式替代圖片(根據需求選擇更合適的圖片格式,jpg適合色彩較多的場景,gif用於較複雜的動畫,png適用於半透明場景),設定合理的快取,圖片懶載入(非可視區不載入)等等

懶載入

首先在渲染時,圖片引用預設圖片,然後把真實地址放在data-*屬性上面


<image src='./../assets/default.png' :data-src='item.allPics' class='lazyloadimg'>
 然後是監聽滾動,直接用window.onscroll就可以了,但是要注意一點的是類似於window的scroll和resize,還有mousemove這類觸發很頻繁的事件,最好用節流(throttle)或防抖函式(debounce)來控制一下觸發頻率。underscore和lodash裡面都有封裝這兩個方法,這裡先不多做介紹了。

接著要判斷圖片是否出現在了視窗裡面,主要是三個高度:1,當前body從頂部滾動了多少距離。2,視窗的高度。3,當前圖片距離頂部的距離。

<image src='./../assets/default.png' :data-src='item.allPics' class='lazyloadimg'>
<image src='./../assets/default.png' :data-src='item.allPics' class='lazyloadimg'>
<image src='./../assets/default.png' :data-src='item.allPics' class='lazyloadimg'>


window.onscroll =_.throttle(this.watchscroll, 200);
watchscroll () {
  var bodyScrollHeight =  document.body.scrollTop;// body滾動高度
  var windowHeight = window.innerHeight;// 視窗高度
  var imgs = document.getElementsByClassName('lazyloadimg');
  for (var i =0; i < imgs.length; i++) {
    var imgHeight = imgs[i].offsetTop;// 圖片距離頂部高度  
    if (imgHeight  < windowHeight  + bodyScrollHeight) {
       imgs[i].src = imgs[i].getAttribute('data-src');
       img[i].className = img[i].className.replace('lazyloadimg','')
    }
  }
}

其他常見判斷:

1.頁面滾動離開首屏(這時可顯示回到頂部的按鈕):document.body.scrollTop > window.innerHeight
2.頁面滾動到底部了(這時可去調介面獲取更多內容):

window.scrollY + window.innerHeight > document.body.offsetHeight

總結一下下:

 網頁被捲起來的高度/寬度(即瀏覽器滾動條滾動後隱藏的頁面內容高度)

(javascript)        document.documentElement.scrollTop //firefox

(javascript)        document.documentElement.scrollLeft //firefox

(javascript)        document.body.scrollTop //IE

(javascript)        document.body.scrollLeft //IE

(jqurey)             $(window).scrollTop() 

(jqurey)             $(window).scrollLeft()

 網頁工作區域的高度和寬度  

(javascript)       document.documentElement.clientHeight// IE firefox       

(jqurey)             $(window).height()

 元素距離文件頂端和左邊的偏移值  

(javascript)        DOM元素物件.offsetTop //IE firefox

(javascript)        DOM元素物件.offsetLeft //IE firefox

(jqurey)             jq物件.offset().top

(jqurey)             jq物件.offset().left

 頁面元素距離瀏覽器工作區頂端的距離  =  元素距離文件頂端偏移值  -   網頁被捲起來的高度  ,即:

 頁面元素距離瀏覽器工作區頂端的距離 =  DOM元素物件.offsetTop  -  document.documentElement.scrollTop 

下面是另一篇文章,詳細一點

大部分轉載自:http://www.cnblogs.com/flyromance/p/5042187.html

示例(懶載入和回到頂部)http://blog.csdn.net/weixin_35955795/article/details/54411516

一、什麼是圖片滾動載入?

  通俗的講就是:當訪問一個頁面的時候,先把img元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就只需請求一次),只有當圖片出現在瀏覽器的可視區域內時,才設定圖片正真的路徑,讓圖片顯示出來。這就是圖片懶載入。

二、為什要使用這個技術?

  比如一個頁面中有很多圖片,如淘寶、京東首頁等等,如果一上來就傳送這麼多請求,頁面載入就會很漫長,如果js檔案都放在了文件的底部,恰巧頁面的頭部又依賴這個js檔案,那就不好辦了。更為要命的是:一上來就傳送百八十個請求,伺服器可能就吃不消了(又不是隻有一兩個人在訪問這個頁面)。

  因此優點就很明顯了:不僅可以減輕伺服器的壓力,而且可以讓載入好的頁面更快地呈現在使用者面前(使用者體驗好)。

三、怎麼實現?

  關鍵點如下:

      1、頁面中的img元素,如果沒有src屬性,瀏覽器就不會發出請求去下載圖片(也就沒有請求咯,也就提高效能咯),一旦通過javascript設定了圖片路徑,瀏覽器才會送請求。有點按需分配的意思,你不想看,就不給你看,你想看了就給你看~

  2、如何獲取正真的路徑,這個簡單,現在正真的路徑存在元素的“data-url”(這個名字起個自己認識好記的就行)屬性裡,要用的時候就取出來,再設定;

  3、開始比較之前,先了解一些基本的知識,比如說如何獲取某個元素的尺寸大小、滾動條滾動距離偏移位置距離(主要是比較這兩項,瀏覽器距文件距離、元素距文件距離,兩者相比較,就能判斷元素位置,scroll、client、offset);

 

  1)螢幕可視視窗大小:對應於圖中1、2位置處

    原生方法:window.innerHeight 標準瀏覽器及IE9+ || document.documentElement.clientHeight 標準瀏覽器及低版本IE標準模式 ||

           document.body.clientHeight 低版本混雜模式

       jQuery方法: $(window).height() 

  2)瀏覽器視窗頂部與文件頂部之間的距離,也就是滾動條滾動的距離:也就是圖中3、4處對應的位置;

    原生方法:window.pagYoffset——IE9+及標準瀏覽器 || document.documentElement.scrollTop 相容ie低版本的標準模式 ||

         document.body.scrollTop 相容混雜模式;

        jQuery方法:$(document).scrollTop(); 

  3)獲取元素的尺寸:對應於圖中5、6位置處;左邊jquery方法,右邊原生方法

    $(o).width() = o.style.width; 

    $(o).innerWidth() = o.style.width+o.style.padding;

    $(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border;

    $(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin;

    注意:要使用原生的style.xxx方法獲取屬性,這個元素必須已經有內嵌的樣式,如<div style="...."></div>;

    如果原先是通過外部或內部樣式表定義css樣式,必須使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]來獲取樣式值

  4)獲取元素的位置資訊:對應與圖中7、8位置處

    1)返回元素相對於文件document頂部、左邊的距離;

    jQuery:$(o).offset().top元素距離文件頂的距離,$(o).offset().left元素距離文件左邊緣的距離

    原生:getoffsetTop(),高程上有具體說明,這邊就忽略了;

      順便提一下返回元素相對於第一個以定位的父元素的偏移距離,注意與上面偏移距的區別;

        jQuery:position()返回一個物件,$(o).position().left = style.left,$(o).position().top = style.top;

  4、知道如何獲取元素尺寸、偏移距離後,接下來一個問題就是:如何判斷某個元素進入或者即將進入可視視窗區域?下面也通過一張圖來說明問題。

    1)外面最大的框為實際頁面的大小,中間淺藍色的框代表父元素的大小,物件1~8代表元素位於頁面上的實際位置;以水平方向來做如下說明!

    2)物件8左邊界相對於頁面左邊界的偏移距離(offsetLeft)大於父元素右邊界相對於頁面左邊界的距離,此時可判讀元素位於父元素之外;

    3)物件7左邊界跨過了父元素右邊界,此時:物件7左邊界相對於頁面左邊界的偏移距離(offsetLeft)小於 父元素右邊界相對於

      頁面左邊界的距離,因此物件7就進入了父元素可視區;

    4)在物件6的位置處,物件5的右邊界與頁面左邊界的距離 大於 父元素左邊界與頁面左邊界的距離;

    5)在物件5位置處時,物件5的右邊界與頁面左邊界的距離 小於 父元素左邊界與頁面左邊界的距離;此時,可判斷元素處於父元素可視區外;

    6)因此水平方向必須買足兩個條件,才能說明元素位於父元素的可視區內;同理垂直方向也必須滿足兩個條件;