JS進階篇--怎樣實現圖片的懶加載以及jquery.lazyload.js的使用

在項目中有時候會用到圖片的延遲加載,那麼延遲加載的好處是啥呢?php

我以爲主要包括兩點吧,第一是在包含不少大圖片長頁面中延遲加載圖片能夠加快頁面加載速度;第二是幫助下降服務器負擔。css

下面介紹一下經常使用的延遲加載插件jquery.lazyload.js以及怎樣實現一個延遲加載的插件。html

一:jquery.lazyload.js插件

lazyload是jQuery寫的延遲加載插件,在瀏覽器可視區域外的圖片不會被載入, 直到用戶將頁面滾動到它們所在的位置. 這與圖片預加載的處理方式正好是相反的。node

實現原理

首先選中的img元素都綁定了一個appear事件(處理img顯示真實的圖片地址),方便之後知足條件時觸發該事件;jquery

在配置對象中有一個container屬性配置,默認爲window,若是img元素在該container容器視口中,則觸發appear事件;數組

爲了判斷img元素是否在container容器視口範圍中,有以下四個方法:瀏覽器

$.belowthefold = function(element, settings) {};    // 在視口下方
$.rightoffold = function(element, settings) {};        // 在視口右方
$.abovethetop = function(element, settings) {};        // 在視口上方
$.leftofbegin = function(element, settings) {};        // 在視口左方

具體使用

1.頁面引入方式

因爲延遲加載lazyload是依賴jquery的,全部頁面須要引入jquery,以下:服務器

<script src="jquery.js"></script>
<script src="jquery.lazyload.js"></script>

基本寫法:app

<img class="lazy" data-original="img/example.jpg" width="640" height="480">

$(function() {
    $("img.lazy").lazyload();
});

其中的data-original 屬性存放真實的圖片url路徑。iphone

小貼士:你必須設置圖片的寬度或者高度在css中,不然插件可能不能正常工做。

設置Threshold

默認狀況下圖片會出如今屏幕時加載. 若是你想提早加載圖片, 能夠設置 threshold 選項, 設置 threshold 爲 200 令圖片在距離屏幕 200 像素時提早加載。

$("img.lazy").lazyload({
    threshold : 200
});

設置事件觸發加載

事件能夠是任何 jQuery 事件, 如: click 和 mouseover. 你還可使用自定義的事件, 如: sporty 和 foobar. 默認狀況下處於等待狀態, 直到用戶滾動到窗口上圖片所在位置. 在灰色佔位圖片被點擊以前阻止加載圖片, 你能夠這樣作:

$("img.lazy").lazyload({
    event : "click"
});

固然,你也能夠用下面的這種方式實現延遲加載:

$(function() {
    $("img.lazy").lazyload({
        event : "sporty"
    });
});

$(window).bind("load", function() {
    var timeout = setTimeout(function() {
        $("img.lazy").trigger("sporty")
    }, 5000);
});

便是頁面加載完成 5 秒後,再去執行圖片的懶加載。

延遲加載效果

當圖片徹底加載的時候, 插件默認地使用 show() 方法來將圖顯示出來. 其實你可使用任何你想用的特效來處理. 下面的代碼使用 FadeIn 效果:

$("img.lazy").lazyload({
    effect : "fadeIn"
});

不支持JavaScript的瀏覽器的使用方式

幾乎全部瀏覽器的 JavaScript 都是激活的. 然而可能你仍但願能在不支持 JavaScript 的客戶端展現真實圖片. 當瀏覽器不支持 JavaScript 時優雅降級, 你能夠將真實的圖片片斷在寫 <noscript> 標籤內。

<img class="lazy" data-original="img/example.jpg"  width="640" heigh="480">
<noscript>
    <img src="img/example.jpg" width="640" heigh="480">
</noscript>

能夠經過 CSS 隱藏佔位符:

.lazy {
  display: none;
}

在支持 JavaScript 的瀏覽器中, 你必須在 DOM ready 時將佔位符顯示出來, 這能夠在插件初始化的同時完成。

$("img.lazy").show().lazyload();

設置延遲加載的圖片容器

你能夠將插件用在可滾動容器的圖片上, 例如帶滾動條的 DIV 元素. 你要作的只是將容器定義爲 jQuery 對象並做爲參數傳到初始化方法裏面:

#container {
    height: 600px;
    overflow: scroll;
}

$("img.lazy").lazyload({
    container: $("#container")
});

當圖片不順序排列

滾動頁面的時候, Lazy Load 會循環爲加載的圖片. 在循環中檢測圖片是否在可視區域內. 默認狀況下在找到第一張不在可見區域的圖片時中止循環. 圖片被認爲是流式分佈的, 圖片在頁面中的次序和 HTML 代碼中次序相同. 可是在一些佈局中, 這樣的假設是不成立的. 不過你能夠經過 failurelimit 選項來控制加載行爲。

$("img.lazy").lazyload({ 
    failure_limit : 10
});

將 failurelimit 設爲 10 令插件找到 10 個不在可見區域的圖片是才中止搜索. 若是你有一個猥瑣的佈局, 請把這個參數設高一點。

設置加載隱藏的圖片

可能在你的頁面上埋藏可不少隱藏的圖片. 好比插件用在對列表的篩選, 你能夠不斷地修改列表中各條目的顯示狀態. 爲了提高性能, Lazy Load 默認忽略了隱藏圖片. 若是你想要加載隱藏圖片, 請將 skip_invisible 設爲 false。

$("img.lazy").lazyload({
    skip_invisible : true
});

源碼

官網地址:http://appelsiini.net/project...

/*!
     * Lazy Load - jQuery plugin for lazy loading images
     *
     * Copyright (c) 2007-2015 Mika Tuupola
     *
     * Licensed under the MIT license:
     *   http://www.opensource.org/licenses/mit-license.php
     *
     * Project home:
     *   http://www.appelsiini.net/projects/lazyload
     *
     * Version:  1.9.7
     *
     */
    
    (function($, window, document, undefined) {
        var $window = $(window);
    
        $.fn.lazyload = function(options) {
            var elements = this;
            var $container;
            var settings = {
                threshold       : 0,
                failure_limit   : 0,
                event           : "scroll",
                effect          : "show",
                container       : window,
                data_attribute  : "original",
                skip_invisible  : false,
                appear          : null,
                load            : null,
                placeholder     : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"
            };
    
            function update() {
                var counter = 0;
    
                elements.each(function() {
                    var $this = $(this);
                    if (settings.skip_invisible && !$this.is(":visible")) {
                        return;
                    }
                    if ($.abovethetop(this, settings) ||
                        $.leftofbegin(this, settings)) {
                            /* Nothing. */
                    } else if (!$.belowthefold(this, settings) &&
                        !$.rightoffold(this, settings)) {
                            $this.trigger("appear");
                            /* if we found an image we'll load, reset the counter */
                            counter = 0;
                    } else {
                        if (++counter > settings.failure_limit) {
                            return false;
                        }
                    }
                });
    
            }
    
            if(options) {
                /* Maintain BC for a couple of versions. */
                if (undefined !== options.failurelimit) {
                    options.failure_limit = options.failurelimit;
                    delete options.failurelimit;
                }
                if (undefined !== options.effectspeed) {
                    options.effect_speed = options.effectspeed;
                    delete options.effectspeed;
                }
    
                $.extend(settings, options);
            }
    
            /* Cache container as jQuery as object. */
            $container = (settings.container === undefined ||
                          settings.container === window) ? $window : $(settings.container);
    
            /* Fire one scroll event per scroll. Not one scroll event per image. */
            if (0 === settings.event.indexOf("scroll")) {
                $container.bind(settings.event, function() {
                    return update();
                });
            }
    
            this.each(function() {
                var self = this;
                var $self = $(self);
    
                self.loaded = false;
    
                /* If no src attribute given use data:uri. */
                if ($self.attr("src") === undefined || $self.attr("src") === false) {
                    if ($self.is("img")) {
                        $self.attr("src", settings.placeholder);
                    }
                }
    
                /* When appear is triggered load original image. */
                $self.one("appear", function() {
                    if (!this.loaded) {
                        if (settings.appear) {
                            var elements_left = elements.length;
                            settings.appear.call(self, elements_left, settings);
                        }
                        $("<img />")
                            .bind("load", function() {
    
                                var original = $self.attr("data-" + settings.data_attribute);
                                $self.hide();
                                if ($self.is("img")) {
                                    $self.attr("src", original);
                                } else {
                                    $self.css("background-image", "url('" + original + "')");
                                }
                                $self[settings.effect](settings.effect_speed);
    
                                self.loaded = true;
    
                                /* Remove image from array so it is not looped next time. */
                                var temp = $.grep(elements, function(element) {
                                    return !element.loaded;
                                });
                                elements = $(temp);
    
                                if (settings.load) {
                                    var elements_left = elements.length;
                                    settings.load.call(self, elements_left, settings);
                                }
                            })
                            .attr("src", $self.attr("data-" + settings.data_attribute));
                    }
                });
    
                /* When wanted event is triggered load original image */
                /* by triggering appear.                              */
                if (0 !== settings.event.indexOf("scroll")) {
                    $self.bind(settings.event, function() {
                        if (!self.loaded) {
                            $self.trigger("appear");
                        }
                    });
                }
            });
    
            /* Check if something appears when window is resized. */
            $window.bind("resize", function() {
                update();
            });
    
            /* With IOS5 force loading images when navigating with back button. */
            /* Non optimal workaround. */
            if ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) {
                $window.bind("pageshow", function(event) {
                    if (event.originalEvent && event.originalEvent.persisted) {
                        elements.each(function() {
                            $(this).trigger("appear");
                        });
                    }
                });
            }
    
            /* Force initial check if images should appear. */
            $(document).ready(function() {
                update();
            });
    
            return this;
        };
    
        /* Convenience methods in jQuery namespace.           */
        /* Use as  $.belowthefold(element, {threshold : 100, container : window}) */
    
        $.belowthefold = function(element, settings) {
            var fold;
    
            if (settings.container === undefined || settings.container === window) {
                fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop();
            } else {
                fold = $(settings.container).offset().top + $(settings.container).height();
            }
    
            return fold <= $(element).offset().top - settings.threshold;
        };
    
        $.rightoffold = function(element, settings) {
            var fold;
    
            if (settings.container === undefined || settings.container === window) {
                fold = $window.width() + $window.scrollLeft();
            } else {
                fold = $(settings.container).offset().left + $(settings.container).width();
            }
    
            return fold <= $(element).offset().left - settings.threshold;
        };
    
        $.abovethetop = function(element, settings) {
            var fold;
    
            if (settings.container === undefined || settings.container === window) {
                fold = $window.scrollTop();
            } else {
                fold = $(settings.container).offset().top;
            }
    
            return fold >= $(element).offset().top + settings.threshold  + $(element).height();
        };
    
        $.leftofbegin = function(element, settings) {
            var fold;
    
            if (settings.container === undefined || settings.container === window) {
                fold = $window.scrollLeft();
            } else {
                fold = $(settings.container).offset().left;
            }
    
            return fold >= $(element).offset().left + settings.threshold + $(element).width();
        };
    
        $.inviewport = function(element, settings) {
             return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) &&
                    !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
         };
    
        /* Custom selectors for your convenience.   */
        /* Use as $("img:below-the-fold").something() or */
        /* $("img").filter(":below-the-fold").something() which is faster */
    
        $.extend($.expr[":"], {
            "below-the-fold" : function(a) { return $.belowthefold(a, {threshold : 0}); },
            "above-the-top"  : function(a) { return !$.belowthefold(a, {threshold : 0}); },
            "right-of-screen": function(a) { return $.rightoffold(a, {threshold : 0}); },
            "left-of-screen" : function(a) { return !$.rightoffold(a, {threshold : 0}); },
            "in-viewport"    : function(a) { return $.inviewport(a, {threshold : 0}); },
            /* Maintain BC for couple of versions. */
            "above-the-fold" : function(a) { return !$.belowthefold(a, {threshold : 0}); },
            "right-of-fold"  : function(a) { return $.rightoffold(a, {threshold : 0}); },
            "left-of-fold"   : function(a) { return !$.rightoffold(a, {threshold : 0}); }
        });
    
    })(jQuery, window, document);

二:手寫一個簡單的懶加載插件

js代碼

window.smallDelay = (function(window, document, undefined) {
    'use strict';
    var store = [],poll;
    var settings = {
        offset:0, //離可視區域多少像素的圖片能夠被加載
        throttle: 250 //圖片延時多少毫秒加載
    }
        
    var _inView = function(el) {
        var coords = el.getBoundingClientRect();
        return ((coords.top >= 0 && coords.left >= 0) && coords.top <= ((window.innerHeight || document.documentElement.clientHeight) + parseInt(settings.offset)));
    };

    var _pollImages = function() {
        for (var i = store.length; i--;) {
            var self = store[i];
            if (_inView(self)) {
                self.src = self.getAttribute('data-delay');
                store.splice(i, 1);
            }
        }
    };

    var _throttle = function() {
        clearTimeout(poll);
        poll = setTimeout(_pollImages, settings.throttle);
    };

    var init = function(obj) {
        var nodes = document.querySelectorAll('[data-delay]');
        var opts = obj || {};
        settings.offset = opts.offset || settings.offset;
        settings.throttle = opts.throttle || settings.throttle;

        for (var i = 0; i < nodes.length; i++) {
            store.push(nodes[i]);
        }

        _throttle();
        
        //滾動監聽執行圖片懶加載
        if (document.addEventListener) {
            window.addEventListener('scroll', _throttle, false);
        } else {
            window.attachEvent('onscroll', _throttle);
        }
        
        //返回該對象進行鏈式操做
        return this;
    };

    return {
        init: init,
        render: _throttle
    };

})(window, document);

調用方式:

smallDelay.init({
     offset: 0,//離可視區域多少像素的圖片能夠被加載
   throttle: 0 //圖片延時多少毫秒加載
});

html代碼:

<img src="images/loading.gif" data-delay="images/avatar.png" />

三:根據lazyload插件實現一個不依賴jQuery的懶加載插件

實現內容

一、增長了圖片預加載可選

二、修改了圖片自己就在可視範圍的時候直接顯示而不須要滾動條觸發

三、修改了Splice刪除數組的時候,會跳過下一張圖片BUG

四、瀏覽器窗口resize的時候圖片出現也會加載

五、判斷圖片父層包裹頂部或者底部出如今可視範圍內便可顯示圖片

實現源碼

var Lazy = {
        $:function(arg,context){
            var tagAll,n,eles=[],i,sub = arg.substring(1);
            context = context|| document;
            if(typeof arg =='string'){
                switch(arg.charAt(0)){
                    case '#':
                        return document.getElementById(sub);
                        break;
                    case '.':
                        if(context.getElementsByClassName) return context.getElementsByClassName(sub);
                        tagAll = Lazy.$('*');
                        n = tagAll.length;
                        for(i = 0;i<n;i++){
                            if(tagAll[i].className.indexOf(sub) > -1) eles.push(tagAll[i]);
                        }
                        return eles;
                        break;
                    default:
                        return context.getElementsByTagName(arg);
                        break;
                }
            }
        },
        getPos:function (node) {
            var scrollx = document.documentElement.scrollLeft || document.body.scrollLeft,
                    scrollt = document.documentElement.scrollTop || document.body.scrollTop;
            var pos = node.getBoundingClientRect();
            return {top:pos.top + scrollt, right:pos.right + scrollx, bottom:pos.bottom + scrollt, left:pos.left + scrollx }
        },
        bind:function(node,type,handler){
            node.addEventListener?node.addEventListener(type, handler, false):node.attachEvent('on'+ type, handler);
        },
        unbind:function(node,type,handler){
            node.removeEventListener?node.removeEventListener(type, handler, false):node.detachEvent('on'+ type, handler);
        },
        toArray:function(eles){
            var arr = [];
            for(var i=0,n=eles.length;i<n;i++){
                arr.push(eles[i]);
            }
            return arr;
        }
    };
    function imgLazyLoad(){
        var timer,screenHeight = document.documentElement.clientHeight;
        // 選擇全部圖片
        var allimg = Lazy.$('img');
        // 篩選CLASS爲lazyload的圖片
        var elems = Lazy.$('.lazyload',allimg);
        // 轉換爲真正的數組
        elems = Lazy.toArray(elems);
        if(!elems.length) return;
        // 沒有發生滾動事件時若是圖片在可視範圍以內,也顯示
        for(var i = 0;i < elems.length;i++){
            // 獲取圖像的父元素即包裹圖像的元素,判斷圖像是否在可視區域即直接判斷父元素是否可視
            var parent = elems[i].parentNode;
            var pos = Lazy.getPos(parent);
            var posT = pos.top;
            var posB = pos.bottom;
            // 沒有滾動條狀況若是距離頂部的距離小於屏幕的高度則賦值SRC
            if(posT < screenHeight){
                elems[i].src = elems[i].getAttribute('data-img');
                // 移除後,數組的長度減一,下一個下標需減一
                elems.splice(i--,1);
            }
        }
        // 綁定scroll事件
        Lazy.bind(window,'scroll',loading);
        Lazy.bind(window,'resize',loading);
        function loading(){
            timer && clearTimeout(timer);
            timer = setTimeout(function(){
                var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                screenHeight = document.documentElement.clientHeight;
                for(var i = 0;i < elems.length;i++){
                    var parent = elems[i].parentNode;
                    var pos = Lazy.getPos(parent);
                    var posT = pos.top;
                    var posB = pos.bottom;
                    var screenTop = screenHeight+scrollTop;
                    // 元素頂部出如今可視區  或者  元素底部出如今可視區
                    if((posT > scrollTop && posT <  screenTop) || (posB > scrollTop && posB < screenTop)){
                        elems[i].src = elems[i].getAttribute('data-img');
                        elems.splice(i--,1);
                    }else{
                        // 去掉如下注釋開啓圖片預加載
                        // new Image().src = elems[i].getAttribute('data-img');
                    }
                }
                if(!elems.length){
                    Lazy.unbind(window,'scroll',loading);
                    Lazy.unbind(window,'resize',loading);
                }
            },300);
        }
    }
    imgLazyLoad();

使用方法

一、在圖片上增長lazyload的類(class='lazyload')

二、把真實的圖片地址放入自定義屬性data-img 中,把圖片的SRC屬性設置爲一個一像素的透明圖片,圖片須要設置width,height屬性,以避免佈局混亂

以下:

<img data-img="a.jpg" src="loading.gif" width="640" height="480"   class='lazyload'>

三、在須要延遲加載的頁面調用imgLazyLoad()函數;

該原生js實現的懶加載轉載地址:http://www.cnblogs.com/NNUF/a...

相關文章
相關標籤/搜索