如何實現一個圖片懶加載庫

幾個月前實現的一個圖片懶加載庫lazyload.jsgithub 地址。javascript

須要實現的效果

相信你們都在網頁中體驗過圖片懶加載,它應該有這樣的效果:當圖片進入咱們的可視區時,加載這些圖片。其緣由相信你們都懂的——提升用戶體驗。java

那麼在代碼中,咱們就應該實現一下幾點功能:
1.當頁面加載完成時,先對可視區的圖片進行加載;
2.給 scrollresize 事件添加監聽;
3.當上述事件觸發時,對在可視區的圖片進行加載,並將加載過的圖片移除。git

具體實現

通過上面的分析,咱們一步一步來實現圖片懶加載。首先,咱們先制定一些規則:
1.須要懶加載的圖片標籤應該帶有值爲 lazyload-img 的類;
2.須要懶加載的圖片標籤應該帶有屬性 data-src ,其值爲圖片的連接。github

定義懶加載構造函數

function LazyLoad() {
    // 將全部須要懶加載的圖片緩存在 imgList 數組中
    this.imgList = [].slice.call(document.querySelectorAll(".lazyload-img"));
    // 進行初始化操做
    this.init();
}

接下來想一想咱們的 init 方法應該作些什麼?圖片的加載是經過事件觸發實現的,因此我在初始化的方法主要作的事情就是添加事件監聽。數組

init 方法的實現放到最後來說,接下來先來實現判斷圖片是否在可視區的方法 isInViewport瀏覽器

isInViewport方法的實現

在上代碼前先來說講 getBoundingClientRect 這貨,不知道你們對她瞭解多少。MDN上給出的定義是這樣的:緩存

  • Element.getBoundingClientRect()方法返回元素的大小及其相對於視口的位置。函數

什麼意思呢,就是調用了這個方法後,返回了一個包含元素的寬高及其相對於瀏覽器視口左上角的位置信息。嗯.. 沒看懂:( 簡單點說呢,這個方法返回了一個對象,長這樣:優化

{
    bottom: xx,
    left: xx,
    right: xx,
    top: xx,
    height: xx,
    width: xx
}

若是仍是不太明白,能夠直接到MDN看看。建議你們直接在控制檯試試,說得再多不如動手試一試。
那瞭解這個方法後,有啥用?固然是用來判斷圖片是否在可視區咯,那咱們來看看判斷的邏輯:this

LazyLoad.prototype.isInViewport = function (img) {
    var clientH = document.documentElement.clientHeight, // 瀏覽器視口高度
        clientW = document.documentElement.clientWidth, // 瀏覽器視口寬度
        imgPosOb = img.getBoundingClientRect(), // 獲取img的位置信息
        imgT = imgPosOb.top,
        imgL = imgPosOb.left,
        imgH = imgPosOb.height,
        imgW = imgPosOb.width;

    // 判斷邏輯
    // 不清楚的同窗能夠在草稿紙上畫個圖
    if( (imgT > -imgH && imgT < clientH) && (imgL > -imgW && imgL < clientW) ) {
        // inViewport
        return true;
    } else {
        return false;
    }
}

咱們還有什麼功能沒實現?固然還有最重要的加載!

實現圖片加載

這一步沒啥好說的,直接上代碼:

// 參數 imgList 是要加載的圖片列表
LazyLoad.prototype.loadImg = function (inVpImgList) {
    var len = inVpImgList.length;
    var src = '';

    for (var i = 0; i < len; i++) {
        src = inVpImgList[i].getAttribute("data-src");
        inVpImgList[i].src = src;
        inVpImgList[i].removeAttribute("data-src");
        this.removeItem(inVpImgList[i]);
    }
};

// 不要忘了這一步
// 把加載過的圖片移除
LazyLoad.prototype.removeItem = function (img) {
    var idx = this.imgList.indexOf(img);
    if(idx > -1) {
        this.imgList.splice(idx, 1);
    }
};

init方法的實現

最後,來完成咱們的初始化方法:

LazyLoad.prototype.init = function () {
    var self = this;

    // callback函數即咱們定義的事件觸發後的回調函數
    function callback() {
        var imgInVp = [];
        var len = self.imgList.length;

        for (var i = 0; i < len; i++) {
            if(self.isInViewport(self.imgList[i])) {
                imgInVp.push(self.imgList[i]);
            }
        }

        self.loadImg(imgInVp);
    }

    callback();

    document.addEventListener("scroll", callback, false);
    window.addEventListener("resize", callback, false);
};

可能有哪位細心的小夥伴會發現我在 init 方法中調用了一次 callback。讓咱們再回頭看看功能分析的第一點,你就明白了。那到這咱就完事了?不,還得優化一下。

優化

咱們知道當咱們在短期內,連續地改變瀏覽器窗口大小或者滾動頁面,會連續屢次地觸發 resizescroll 事件。而這是咱們能夠優化的地方,這裏咱們使用函數去抖,調整後的代碼以下:

LazyLoad.prototype.init = function () {
    var self = this,
        timer = null;

    function callback() {
        timer && clearTimeout(timer);
        timer = setTimeout(function () {
            var imgInVp = [];
            var len = self.imgList.length;

            for (var i = 0; i < len; i++) {
                if(self.isInViewport(self.imgList[i])) {
                    imgInVp.push(self.imgList[i]);
                }
            }

            self.loadImg(imgInVp);
        }, 100);
    }

    callback();

    document.addEventListener("scroll", callback, false);
    window.addEventListener("resize", callback, false);
};

至此,也算是實現了一個簡單的圖片懶加載庫了,若有不足之處歡迎指正,你們一塊兒交流交流 :)

相關文章
相關標籤/搜索