圖片懶加載

爲何要懶加載?

懶加載是一種網頁性能優化的方式,它能極大的提高用戶體驗。css

假如訪問某個頁面,加載這個頁面所有的圖片(即便這些圖片並不處在用戶的當前的視窗中),在弱網環境或者網速較慢的環境下,這些「冗餘」圖片的下載會佔用用戶原本就很是有限的帶寬,影響用戶體驗因此對於網站的圖片,優化的方法就是懶加載(按需加載)。vue

實現原理

進入頁面的時候,只請求可視區域的圖片資源, 不在可視區域內的圖片,等將要出現時動態加載。node

將img標籤src設置爲一張默認小圖片,而後定義data-src(這個屬性能夠自定義命名,我才用data-src)屬性指向真實的圖片。src需設置一張默認的圖片,不然當src爲空時也會向服務器發送一次請求。git

一個簡單的實現

設置data-src, 經過js加載真正的圖片。github

// img-load.css
img[data-src] {
  filter: blur(0.2em);
}

img {
  filter: blur(0em);
  transition: filter 0.5s;
}
// img-load.js

function lazyLoad(){
  const imageToLazy = document.querySelectorAll('img[data-src]');
  const loadImage = function (image) {
    image.setAttribute('src', image.getAttribute('data-src'));
    image.addEventListener('load', function() {
      image.removeAttribute("data-src");
    })
  }

  imageToLazy.forEach(function(image){
    loadImage(image);
  })
}

lazyLoad();

return (
  ...
    ![](deafult.png)
  ...
);

監聽滾動加載圖片

先加載出如今視窗中的圖片, 當頁面將要滾動到不在視窗內的圖片時,加載圖片。性能優化

  1. IntersectionObserver實現當圖片滾動到視窗後再加載該圖片, 考慮到手機兼容性問題須要添加polyfill
(function lazyLoad(){
  let observer;
  const imageToLazy = document.querySelectorAll('img[data-src]');
  
  const loadImage = function (image) {
    image.setAttribute('src', image.getAttribute('data-src'));
    image.addEventListener('load', function() {
      image.removeAttribute("data-src");
    })
  }


  if (window.IntersectionObserver) {
    observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting || entry.intersectionRatio > 0) {
          loadImage(entry.target);
          observer.unobserve(entry.target);
        }
      });
    });
  }

  imageToLazy.forEach(function(image){
    if (window.IntersectionObserver && observer) {
      observer.observe(image);
    } else {
      loadImage(image);
    }
  })
})();
  1. 添加scroll事件實現圖片懶加載。當頁面滾動時,scroll函數會被高頻觸發,須要經過節流或者requestAnimationFrame優化性能。服務器

    判斷圖片是否將要出如今可視區也可根據getBoundingClientRect()判斷函數

    const imgs = document.getElementsByTagName("img");
    const imgLength = imgs.length;
    let currentIndex = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷
    
    const clientHeight = document.documentElement.clientHeight; //可見區域高度
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滾動條距離頂部高度
    
    function lazyload(event) {
      for (let i = currentIndex; i < imgLength; i++) {
        if (clientHeight + scrollTop > imgs[i].offsetTop) {
          if (imgs[i].getAttribute("src") == "default.jpg") {
            imgs[i].src = img[i].getAttribute("data-src");
          }
          currentIndex = i + 1;
        }
      }
    }
    window.addEventListener('scroll',throttle(lazyload, 500, 1000));
  2. vue指令實現圖片懶加載
let timer = null;
let observer;

if (window.IntersectionObserver) {
  observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting || entry.intersectionRatio > 0) {
        if (!entry.target.isLoaded) {
          showImage(entry.target, entry.target.data_src);
        }
      }
    });
  });
}

function showImage(el, imgSrc) {
  const img = new Image();
  img.src = imgSrc;
  img.onload = () => {
    el.src = imgSrc;
    el.isLoaded = true;
  };
}

export default {
  inserted(el, binding, vnode) {
    el.data_src = binding.value;
    if (window.IntersectionObserver && observer) {
      clearTimeout(timer);
      observer.observe(el);
      const vm = vnode.context;
      timer = setTimeout(() => {
        vm.$on('hook:beforeDestroy', () => {
          observer.disconnect();
        });
      }, 20);
    } else {
      el.src = binding.value;
    }
  },
  update(el, binding) {
    if (window.IntersectionObserver && observer) {
      el.isLoaded = el.data_src !== binding.value;
      el.data_src = binding.value;
    } else {
      el.src = binding.value;
    }
  },
}
相關文章
相關標籤/搜索