所謂圖片的懶加載,即只有當圖片處於或者接近於當前視窗時纔開始加載圖片。該庫的使用方法很是簡單:node
var layzr = new Layzr({ attr: 'data-layzr', // attr和retinaAttr必須至少有一個,用於指定對應的圖片 retinaAttr: 'data-layzr-retina', // 通常對應的圖像比attr要高清 threshold: 0, // 距離視窗的距離爲多少時開始加載 callback: null // 回調函數 });
首先是包裝成爲umd的方式:瀏覽器
(function(root, factory) { if(typeof define === 'function' && define.amd) { define([], factory); // 使用amd定義一個模塊,依賴爲空 } else if(typeof exports === 'object') { module.exports = factory(); // cmd方式,暴露返回值 } else { root.Layzr = factory(); // 瀏覽器環境下 } }(this, function() { })
接下來是構造函數:函數
function Layzr( options ) { this._lastScroll = 0; this._ticking = false; // 參數 this._optionsAttr = options.attr || 'data-layzr'; this._optionsAttrRetina = options.retinaAttr || 'data-layzr-retina'; this._optionsThreshold = options.threshold || 0; this._optionsCallback = options.callback || null; // 獲取合適的屬性 this._retina = window.devicePixelRatio > 1; this._imgAttr = this._retina ? this._optionsAttrRetina : this._optionsAttr; // 全部的圖像集合 this._images = document.getElementsByTagName('img'); // call to create this._create(); }
create和destory函數:優化
Layzr.prototype._create = function() { // 記錄初始的scroll位置 this._requestScroll(); // scroll和resize對應的事件處理函數 window.addEventListener('scroll', this._requestScroll.bind(this), false); window.addEventListener('resize', this._requestScroll.bind(this), false); } Layzr.prototype._destroy = function() { // unbind事件 window.removeEventListener('scroll', this._requestScroll.bind(this), false); window.removeEventListener('resize', this._requestScroll.bind(this), false); }
requestScroll的具體實現:this
Layzr.prototype._requestScroll = function() { this._lastScroll = window.scrollY || window.pageYOffset; // 垂直方向上的滾動距離 this._requestTick(); } Layzr.prototype._requestTick = function() { if(!this._ticking) { // requestAnimationFrame主要用於繪製圖像,經過優化提升效率 // 這裏用於每次滾動都調用update requestAnimationFrame(this.update.bind(this)); this._ticking = true; } } Layzr.prototype.update = function() { var imagesLength = this._images.length; for(var i = 0; i < imagesLength; i++) { var image = this._images[i]; // 若是當前的圖片有設定的屬性 if(image.hasAttribute(this._imgAttr) || image.hasAttribute(this._optionsAttr)) { // 且已經處於視窗中 if(this._inViewport(image)) { // 加載這個圖片 this.reveal(image); } } } // allow for more animation frames this._ticking = false; }
是否在視窗中的判斷:spa
Layzr.prototype._inViewport = function( imageNode ) { // 視窗的頂部和底部 var viewportTop = this._lastScroll; var viewportBottom = viewportTop + window.innerHeight; // 圖像的頂部和底部 var elementTop = this._getOffset(imageNode); var elementBottom = elementTop + imageNode.offsetHeight; // 計算threshold對應的像素 var threshold = (this._optionsThreshold / 100) * window.innerHeight; // 是否在這個區間中 return elementBottom >= viewportTop - threshold && elementBottom <= viewportBottom + threshold; }
展現圖像的實現:prototype
Layzr.prototype.reveal = function( imageNode ) { // 獲取圖像的src var source = imageNode.getAttribute(this._imgAttr) || imageNode.getAttribute(this._optionsAttr); // 去除設置的屬性 imageNode.removeAttribute(this._optionsAttr); imageNode.removeAttribute(this._optionsAttrRetina); //設置src if(source) { imageNode.setAttribute('src', source); // 調用callback if(typeof this._optionsCallback === 'function') { this._optionsCallback.call(imageNode); } } }