天天一點網站優化之:圖片懶加載


title: 天天一點網站優化之:圖片懶加載 date: 2019-05-29 17:00:00 tags: -JavaScript
-closure categories: JavaScript

小c同窗是一名前端程序猿。 這一天,大boss給他下了一個指令:咱們的網站圖片太多太大,太浪費網絡資源了,我要節省流量又不要下降圖片質量,你看着辦吧。 因而,小c同窗想到了圖片懶加載:當圖片沒有出如今用戶屏幕上時,用一張輕量級的佔位圖片代替,圖片出現後用js動態替換爲高質量圖片。 接下來,小c同窗抄起鍵盤開始了敲代碼之旅。。。。。。javascript

要實現圖片懶加載,基本的思路是監聽瀏覽器滾動事件,不斷對比目標元素距離屏幕下方的距離,當目標元素滾動到指定位置時,執行js代碼。html

scrollTop+offsetTop方法

scroll

  1. 網頁當前向上滾動的高度scrollTop
  2. 目標元素距離網頁body頂端的距離
  3. 用戶可見區域高度window.innerHeight 當知足 offsetTop - scrollTop <= innerHeight的時候,表明元素進入可見區域

獲取滾動高度scrollTop

  • pageYOffset屬於window對象,IE9+ 、firefox、chrome,opera均支持該方式獲取頁面滾動高度值,而且會忽略Doctype定義規則。
  • body是DOM對象裏的body子節點,即 body 標籤
  • documentElement是整個節點樹的跟節點,即 html 標籤

在不以上三種不一樣的方法在各類瀏覽器下的兼容性各不相同 兼容性表格以下:前端

瀏覽器\獲取滾動高度方法 window.pageYOffset document.documentElement.scrollTop document.body.scrollTop
chrome Y Y N
firefox Y Y N
IE11及以上 Y Y N
ios Y N Y
android(wchat+原生瀏覽器) Y N Y

完整的兼容性代碼java

var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
複製代碼

網頁高度知多少

image tops
;
image brower
; 網頁可見區域寬:document.body.clientWidth 網頁可見區域高:document.body.clientHeight 網頁可見區域寬:document.body.offsetWidth (包括邊線的寬) 網頁可見區域高:document.body.offsetHeight (包括邊線的寬) 網頁正文全文寬:document.body.scrollWidth 網頁正文全文高:document.body.scrollHeight 網頁被捲去的高:document.body.scrollTop 網頁被捲去的左:document.body.scrollLeft 網頁正文部分上:window.screenTop 網頁正文部分左:window.screenLeft 屏幕分辨率的高:window.screen.height 屏幕分辨率的寬:window.screen.width 屏幕可用工做區高度:window.screen.availHeight 屏幕可用工做區寬度:window.screen.availWidth 窗口不包括工具欄和滾動條高度: window.innerHeight 窗口不包括工具欄和滾動條寬度: window.innerWidth

圖片懶加載是檢測圖片是否進入用戶可見視野,因此選擇window.innerHeight做爲瀏覽器的高度。android

方法實現

let offsetTop = element.offsetTop; //元素相對body左上角的高度
let scrollTop = getScrollTop().top; //網頁滾動高度
let innerHeight = window.innerHeight; //可用窗口高度

if(offsetTop - scrollTop <= innerHeight){
    inViewFun.call(this);
}
複製代碼

該方法的缺點是offsetTop相對父元素來講的,若是目標圖片元素的父元素不是body,則會有問題。ios

利用 getBoundingClientRect 方法

  • element.getBoundingClientRect()方法返回元素的大小及其相對於視口的位置
    image

方法實現

var rect = element.getBoundingClientRect();
if((rect && rect.top) <= window.innerHeight ){//進入視野
    inViewFun.call(this);
}
複製代碼

優化

scroll監聽事件加入防抖

加入固定高度,使圖片預先加載

完整代碼chrome

function lazyLoad(element, inViewFun, fixedTop, a){
    scrollHandler();
    if(window.addEventListener){
        window.addEventListener('scroll',debounce(scrollHandler));
    }else{ //IE
        window.attachEvent('scroll',debounce(scrollHandler));
    }

    //獲取網頁滾動高度
    function getScrollTop(){
        var supportPageOffset = window.pageXOffset !== undefined;
        var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

        var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
        var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
        return {left:x, top:y};
    }

    // function scrollHandler(){
    // let offsetTop = element.offsetTop; //元素相對body左上角的高度
    // let scrollTop = getScrollTop().top; //網頁滾動高度
    // let innerHeight = window.innerHeight; //可用窗口高度

    // if(offsetTop - scrollTop <= innerHeight){
    // inViewFun.call(this);
    // }
    // }

    function scrollHandler(){
        var rect = element.getBoundingClientRect();
        if((rect && rect.top) <= window.innerHeight + fixedTop ){//進入視野
            inViewFun.call(this);
        }
    }
}
複製代碼

intersection observer

圖片懶加載可利用intersection observer, 目前只能在Chrome63+和firefox58+使用 比起事件監聽,Intersection observer用起來比較簡單,可閱讀性也大大提升。開發者只須要註冊一個observer去監控元素而不是寫一大堆亂七八糟的視窗檢測代碼。註冊observer以後咱們只須要作的就是當元素可見時改變它的行爲。瀏覽器

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">
複製代碼
  • class:用於在JavaScript中關聯元素
  • src屬性:指向了一張佔位圖片,圖片在頁面的第一次加載會顯現
  • data-src和data-srcset屬性:這是佔位屬性,裏面放的是目標圖片的url
document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to a more compatible method here
  }
});
複製代碼
相關文章
相關標籤/搜索