實現一個圖片懶加載插件有多難?

源碼地址

插件完整版地址 m-lazy
https://github.com/zhanyouwei...javascript

歡迎一塊兒交流

歡迎關注個人我的公衆號,不按期更新本身的工做心得。
圖片描述java

正文開始

Web 圖片的懶加載就是經過讀取img元素,而後得到img元素的data-src(也能夠約定爲其餘屬性名)屬性的值,並賦予img的src,從而實現動態加載圖片的機制。node

這裏須要注意的是: img在初始化的時候不要設置src屬性,由於即便設置 src='' 瀏覽器也會嘗試加載圖片。git

一個簡單的圖片懶加載共涉及兩個方面,github

1. HTML 約定

咱們首先須要給準備實施懶加載的img元素添加指定的class 這裏爲m-lazyload ,同時將img src賦值給 data-src屬性。
具體示例爲:瀏覽器

<img class="m-lazyload" data-src="imgUrl">

2. JavaScript 實現

動態加載總共分爲如下幾個步驟,這裏每一個步驟都將被拆分爲獨立的函數緩存

1. 添加頁面滾動監聽事件
window.addEventListener('scroll', _delay, false);

function _delay() {
  clearTimeout(delay);
  delay = setTimeout(function () {
    _loadImage();
  }, time);
}
2. 當觸發監聽事件時會執行 _loadImage 函數,該函數負責加載圖片
function _loadImage() {
  for (var i = imgList.length; i--;) {
    var el = imgList[i];
    if (_isShow(el)) {
      el.src = el.getAttribute('data-src');
      el.className = el.className.replace(new RegExp("(\\s|^)" + _selector.substring(1, _selector.length) + "(\\s|$)"), " ");
      imgList.splice(i, 1);
    }
  }
}

雖然執行了_loadImage函數,可是咱們得知道哪些圖片須要被加載,這裏的判斷依據是什麼呢?dom

依據就是判斷該圖片是否在當前窗口的可視區域內,在這裏咱們封裝一個_isShow函數來實現函數

function _isShow(el) {
  var coords = el.getBoundingClientRect();
  return ( (coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight) + parseInt(offset));
}

自此一個圖片加載的閉環就造成了性能

當網頁滾動的事件被觸發 -> 執行加載圖片操做 -> 判斷圖片是否在可視區域內 -> 在,則動態將data-src的值賦予該圖片。

太簡單了?

事實就是如此!!!

如此簡單,不妨擴展一下

  1. 添加一些自定義參數,誰都喜歡自定義,不是嗎?

  2. 支持iScroll, iScroll是一個高性能,資源佔用少,無依賴,多平臺的javascript滾動插件。

這裏咱們作了些優化
  1. 圖片加載後移除選擇器,避免重複判斷。

  2. 緩存img元素結合,減小dom元素查詢性能損耗

  3. 擴展prototype添加getNode方法,支持分頁數據懶加載(因爲咱們以前緩存了dom元素)

OK!說了這麼多,show me the code 吧!

(function () {
  var imgList = [],  // 頁面全部img元素集合
    delay,   // setTimeout 對象
    offset,  //偏移量,用於指定圖片距離可視區域多少距離,進行加載
    time,  // 延遲載入時間
    _selector; // 選擇器 默認爲 .m-lazyload

  function _isShow(el) {
    var coords = el.getBoundingClientRect();
    return ( (coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight) + parseInt(offset));
  }

  function _loadImage() {
    for (var i = imgList.length; i--;) {
      var el = imgList[i];
      if (_isShow(el)) {
        el.src = el.getAttribute('data-src');
        el.className = el.className.replace(new RegExp("(\\s|^)" + _selector.substring(1, _selector.length) + "(\\s|$)"), " ");
        imgList.splice(i, 1);
      }
    }
  }

  function _delay() {
    clearTimeout(delay);
    delay = setTimeout(function () {
      _loadImage();
    }, time);
  }

  function ImageLazyload(selector, options) {
    var defaults = options || {};
    offset = defaults.offset || 0;
    time = defaults.time || 250;
    _selector = selector || '.m-lazyload';
    this.getNode();
    _delay();//避免首次加載未觸發touch事件,主動觸發一次加載函數
    if (defaults.iScroll) {
      defaults.iScroll.on('scroll', _delay);
      defaults.iScroll.on('scrollEnd', _delay);
    } else {
      window.addEventListener('scroll', _delay, false);
    }
  }
  ImageLazyload.prototype.getNode = function () {
    imgList = [];
    var nodes = document.querySelectorAll(_selector);
    for (var i = 0, l = nodes.length; i < l; i++) {
      imgList.push(nodes[i]);
    }
  };
})();
相關文章
相關標籤/搜索