图片懒加载(滚动加载)原理

来源:互联网 发布:win10装mac双系统 编辑:程序博客网 时间:2024/06/01 03:59

一、什么是图片懒加载?

即在页面载入的时候将页面上的img标签的src指向一个小图片,把真实地址存放在一个自定义属性中,这里我用data-src来存放,如下。

<img src="loading.gif" data-src="http://xxx.ooo.com" />

然后将页面img标签获取并保存,开启一个定时器,遍历保存的img标签,判断其位置是否出现在了可视区域内。如果出现在可视区域了那么就把真实的src地址给赋值上。
并且从数组中删除,避免重复判断。我们可以获取当前img的相对于文档顶的偏移距离减去scrollTop的距离,然后和浏览器窗口高度在进行比较,如果小于浏览器窗口则出现在了可视区域内了,反之,则没有。


二、为什要使用这个技术?

对于图片过多的页面,为了加速页面加载速度,比如一个页面中有很多图片,如淘宝、京东首页等等,如果一上来就发送这么多请求,页面加载就会很漫长,如果js文件都放在了文档的底部,恰巧页面的头部又依赖这个js文件,那就不好办了。更为要命的是:一上来就发送百八十个请求,服务器可能就吃不消了(不是只有一两个人在访问这个页面)。
所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。
这样子对于页面加载性能上会有很大的提升,也提高了用户体验。


三、实现


1)屏幕可视窗口大小:对应于图中1、2位置处

    原生方法:window.innerHeight 标准浏览器及IE9+ || document.documentElement.clientHeight 标准浏览器及低版本IE标准模式 ||

           document.body.clientHeight 低版本混杂模式

       jQuery方法: $(window).height() 

  2)浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离:也就是图中3、4处对应的位置;

    原生方法:window.pagYoffset——IE9+及标准浏览器 || document.documentElement.scrollTop 兼容ie低版本的标准模式 ||

         document.body.scrollTop 兼容混杂模式;

        jQuery方法:$(document).scrollTop(); 

  3)获取元素的尺寸:对应于图中5、6位置处;左边jquery方法,右边原生方法

    $(o).width() = o.style.width; 

    $(o).innerWidth() = o.style.width+o.style.padding;

    $(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border;

    $(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin;

    注意:要使用原生的style.xxx方法获取属性,这个元素必须已经有内嵌的样式,如<div style="...."></div>;

    如果原先是通过外部或内部样式表定义css样式,必须使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]来获取样式值

  4)获取元素的位置信息:对应与图中7、8位置处

    1)返回元素相对于文档document顶部、左边的距离;

    jQuery:$(o).offset().top元素距离文档顶的距离,$(o).offset().left元素距离文档左边缘的距离

    原生:getoffsetTop(),高程上有具体说明,这边就忽略了;

      顺便提一下返回元素相对于第一个以定位的父元素的偏移距离,注意与上面偏移距的区别;

        jQuery:position()返回一个对象,$(o).position().left = style.left,$(o).position().top = style.top;


5)知道如何获取元素尺寸、偏移距离后,接下来一个问题就是:如何判断某个元素进入或者即将进入可视窗口区域?

    (1)外面最大的框为实际页面的大小,中间浅蓝色的框代表父元素的大小,对象1~8代表元素位于页面上的实际位置;以水平方向来做如下说明!

    (2)对象8左边界相对于页面左边界的偏移距离(offsetLeft)大于父元素右边界相对于页面左边界的距离,此时可判读元素位于父元素之外;

    (3)对象7左边界跨过了父元素右边界,此时:对象7左边界相对于页面左边界的偏移距离(offsetLeft)小于 父元素右边界相对于

      页面左边界的距离,因此对象7就进入了父元素可视区;

    (4)在对象6的位置处,对象5的右边界与页面左边界的距离 大于 父元素左边界与页面左边界的距离;

    (5)在对象5位置处时,对象5的右边界与页面左边界的距离 小于 父元素左边界与页面左边界的距离;此时,可判断元素处于父元素可视区外;

      (6)因此水平方向必须买足两个条件,才能说明元素位于父元素的可视区内;同理垂直方向也必须满足两个条件。


四、扩展为jquery插件

  使用方法:$("selector").scrollLoad();

(function($) {    $.fn.scrollLoading = function(options) {        var defaults = {            // 在html标签中存放的属性名称;            attr: "data-url",            // 父元素默认为window            container: window,            callback: $.noop        };        // 不管有没有传入参数,先合并再说;        var params = $.extend({}, defaults, options || {});        // 把父元素转为jquery对象;        var container = $(params.container);        // 新建一个数组,然后调用each方法,用于存储每个dom对象相关的数据;        params.cache = [];        $(this).each(function() {            // 取出jquery对象中每个dom对象的节点类型,取出每个dom对象上设置的图片路径            var node = this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]);            //重组,把每个dom对象上的属性存为一个对象;            var data = {                obj: $(this),                tag: node,                url: url            };            // 把这个对象加到一个数组中;            params.cache.push(data);        });        var callback = function(call) {            if ($.isFunction(params.callback)) {                params.callback.call(call);            }        };                //每次触发滚动事件时,对每个dom元素与container元素进行位置判断,如果满足条件,就把路径赋予这个dom元素!        var loading = function() {            // 获取父元素的高度            var contHeight = container.outerHeight();            var contWidth = container.outerWidth();            // 获取父元素相对于文档页顶部的距离,这边要注意了,分为以下两种情况;            if (container.get(0) === window) {                // 第一种情况父元素为window,获取浏览器滚动条已滚动的距离;$(window)没有offset()方法;                var contop = $(window).scrollTop();                var conleft = $(window).scrollLeft();            } else {                // 第二种情况父元素为非window元素,获取它的滚动条滚动的距离;                var contop = container.offset().top;                var conleft = container.offset().left;            }            $.each(params.cache, function(i, data) {                var o = data.obj, tag = data.tag, url = data.url, post, posb, posl, posr;                if (o) {                    //对象顶部与文档顶部之间的距离,如果它小于父元素底部与文档顶部的距离,则说明垂直方向上已经进入可视区域了;                    post = o.offset().top - (contop + contHeight);                    //对象底部与文档顶部之间的距离,如果它大于父元素顶部与文档顶部的距离,则说明垂直方向上已经进入可视区域了;                    posb = o.offset().top + o.height() - contop;                    // 水平方向上同理;                    posl = o.offset().left - (conleft + contWidth);                    posr = o.offset().left + o.width() - conleft;                    // 只有当这个对象是可视的,并且这四个条件都满足时,才能给这个对象赋予图片路径;                    if ( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) {                        if (url) {                            //在浏览器窗口内                            if (tag === "img") {                                //设置图片src                                callback(o.attr("src", url));                            } else {                                // 设置除img之外元素的背景url                                callback(o.css("background-image", "url("+ url +")"));                            }                        } else {                            // 无地址,直接触发回调                            callback(o);                        }                        // 给对象设置完图片路径之后,把params.cache中的对象给清除掉;对象再进入可视区,就不再进行重复设置了;                        data.obj = null;                    }                }            });        };        //加载完毕即执行        loading();        //滚动执行        container.bind("scroll", loading);    };})(jQuery);








原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 工商营业执照年检过期怎么办 个体营业执照没有年报怎么办? 个体工商户一年没有申报怎么办 个体工商户逾期未申报怎么办 个体户没报税过怎么办 农业银行证书过期了怎么办 ca证书丢了怎么办 ca证书被锁怎么办 上个月忘记清卡怎么办 财务人员进入税务黑名单怎么办 社保本丢了怎么办 贷款车辆登记证书怎么办 发票薄丢了怎么办? 汽车发票丢了怎么办 税票弄丢了怎么办 交强险正本丢了怎么办 个体营业执照正本丢失怎么办 简易注销后税务怎么办 拒绝了日历邀请怎么办 老人走丢了怎么办 老人走丢找不到怎么办 没人给介绍对象怎么办 bate365账号被锁怎么办 qq号疑似被盗怎么办 不知道音乐名字怎么办 忘记支付宝登录怎么办 微信被老婆拉黑怎么办 微信群昵称改不了怎么办 微信号设置不了怎么办 修改微信号点不开怎么办 多屏设置失败怎么办 icould密码忘了怎么办 微信号换不了怎么办 微信号改不了怎么办? 无法设置微信号怎么办 公司改名后商标怎么办 公司名称变更后发票怎么办 被起诉公司企业变更怎么办 企业公章坏了怎么办 公司更名旧公章怎么办 手机证书不匹配怎么办