zoukankan      html  css  js  c++  java
  • 【分享】LazyLoad延迟加载(按需加载)

    1:实际需求

      大型网站往往很矛盾,想用户在首页看到更多东西,又不想浪费太多服务器流量。比如一个有3屏的首页。可能50%的用户进首页的目的是点击首页的连接,到子页面。

    那么我们的网站却为100%的用户加载了 3个 屏幕的所有内容。如果可以按需加载内容。就可以节约更多资源,做更多好的应用。

     

    2:解决方案

      用客户端语言来判断用户当前的可视范围,只加载用户可视范围的内容。最主要的是图片。因为文字信息,相对较小,其他多媒体内容相对占用服务器流量更多。

     

    3:演示例子

    4:解析

      首先我们要分析下,这个效果会有一个 最外面的容器。他包涵了里面需要延迟加载一些内容。容器一般可能是浏览器窗口本身(window),或者一个有滚动条的DIV。

    OK,我们必须获取这个容器的一些参数。比如 可视宽度,可视高度,水平卷去宽度,垂直卷去高度。我使用下面的程序。

      4.1:获取容器对象属性

    _this.docInfo=function(){//获取容器的相关信息
    var d={},db= (wf)? document.body : warpper,
    dd
    =(wf) ? document.documentElement : warpper;
    if(sys.ie){
    d.offh
    =dd.offsetHeight;//可视区域H
    d.offw=dd.offsetWidth;//可视区域W
    }else{
    if(wf){
    d.offw
    =window.innerWidth;//可视区域H
    d.offh=window.innerHeight;//可视区域W
    }else{
    d.offh
    =dd.offsetHeight;//可视区域H
    d.offw=dd.offsetWidth;//可视区域W
    }
    }
    d.jtop
    =(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
    d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft : db.scrollLeft;//水平卷去宽度
    //被卷去的宽度 window 使用两个相加 div的卷曲就直接使用scrollLeft就OK
    $j("bbb").innerHTML=d.offh+','+d.offw+','+d.jtop+','+d.jleft
    return d;
    }
    //注意在非IE 浏览器下 获取非window对象的可视区域 使用offsetHeight 和 offsetWidth (跟IE 一样)
    //
    在非IE 下获取 window对象的可视区域 则要使用 window.innerWidth 和window.innerHeight
    //
    也就是说在非IE 下的 window 和 非window 对象的 可视区域获取是不一样的。

      4.2:获取加载内容的信息

        我们主要获取加载对象距离 页面容器对象的距离 。

    IE 6 7会有个BUG

    wtop=sys.ie ? (sys.ie[1]=='6.0' || sys.ie[1]=='7.0') ? 0 : warpper.offsetTop : warpper.offsetTop,
    wleft
    =sys.ie ? (sys.ie[1]=='6.0' || sys.ie[1]=='7.0') ? 0 : warpper.offsetLeft : warpper.offsetLeft,
    getoff=function(o){//获取IMG对象的 offw and offh

    o.innerHTML
    =(o.offsetTop-wtop) +','+ (o.offsetLeft-wleft);
    return (o.offsetTop-wtop) +','+ (o.offsetLeft-wleft);
    //注意 o.offsetTop 在chrome下要等window.onload以后才能正确获取
    };

      4.3:加载主程序

        他主要负责加载当前在可视范围内对象。那么我们必须去遍历所有要加载的对象。判断对象是否在当前的加载中。
    然后加载他。我下面会有一个图。(方法可能不太好)

    _this.Load=function(){
    var hereline=[];
    hereline[
    1]=doc.offh+doc.jtop;
    hereline[
    2]=doc.offw+doc.jleft;

    for(i=0;i<imgs.length;i++){

    if(imgs[i][1] != undefined){//判断当前对象是否已经加载过
    var jj=hereline[1] - imgs[i][1] < doc.offh +130 && hereline[1] - imgs[i][1] > 0 ? true : false,
    jjj
    =hereline[2] - imgs[i][2] < doc.offw +270 && hereline[2] - imgs[i][2] > 0 ? true : false;
    if(jj && jjj){
    imgall[i].innerHTML
    +=''+(++j)+'个加载';
    imgs[i][
    1]=undefined;
    }
    }

    }

    if( j >= imgs.length){//判断是否已经全部加载完毕
    //取消时间绑定
    alert("已经全部加载完成,程序将不再执行")
    warpper.onscroll
    =null;
    warpper.onresize
    =null;
    }
    }

    我不太喜欢我的判断程序,但是暂时没找到,或者我没理解更好的算法。所以就先用这个了。

    大体的意思:用容器的可视高度+容器滚动高度 - 对象距离距离容器距离 > 容器可视 + 对象本身高或宽 就证明在加载范围。(绕口令)

    我们还必须把 已经加载过的对象排除在外。因为加载过的对象也满足以上公式,同时也可以少判断一些。

    imgs[i][1]=undefined;

    if(imgs[i][1!= undefined){//判断当前对象是否已经加载过

      特别注意(看图)

    加载对象图片说明

    看上图 A B C D。 分别有4个不同的角露在了 可视范围内。所以这4个对象是需要加载的。

    如果只考虑对象的某个点,或者某个线来判断对象是否在可视范围,可能带来不好的体验。

    由于有上面这种情况,也给我们的编程(判断是否在可视范围内)增加了难度。

    我上面的方法,是可以完成了。(如果有发现BUG ,请给我指点。其实我也有点晕了。)

    最后还有几个技巧,比如

      1:对象全部加载完了。就应该去掉容器对象事件触发。

      2:尽量优化判断对象是否在可视范围,或者遍历的对象的算法。可以节约很多浏览器资源。

      3:cloudgamer 还提到一个 延迟触发,就是快速的滑动滚动条,延迟一下也是一个小的优化。

    5:推荐文章

      cloudgamer  的 他讲的很详细,也比我做的要好。所以推荐去学习他的这个效果哦。很多东西我也借鉴他的。

    还有就是感谢他的指点。Lazyload 延迟加载效果

    6:我的源码

    代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>lazyload</title>

    </head>

    <body>
    <style type="text/css">
    body
    { margin:0px; padding:0; font-size:12px;}
    .jelle_box
    {width:270px; height:129px; border:1px solid #CCC; float:left;}
    </style>
    <input type="button" value="重新开始" onclick="lazyload().judge();" />
    <div style="100%; height:500px; overflow:scroll; border:2px solid #999;" id="jelle_abcd">
    <div id="aaa" style="2500px; height:800px; margin:10px;">
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    <div class="jelle_box"></div>
    </div>
    </div>
    <div style=" height:30px" id="bbb"></div>
    <script type="text/javascript">
    (
    function(){
    window.lazyload
    =function(){
    var _this={},//方法集合
    imgsurl=['baidu_logo_2.gif']//最开始是用来加载图片的。这里是需要加载图片的地址集合
    imgs=[],//全部IMG 数据 格式为 [[url,offw,offh],[url,offw,offh]]
    i=0,//循环变量
    j=0,//判断当前的加载个数
    warpper=document.getElementById('jelle_abcd'),//window,//容器对象
    wf=(warpper==window) ? true : false;
    doc
    ={offw:0,offh:0,jtop:0,jleft:0},//包含一些 容器对象当前的一些属性
    sys=(function(){//不必紧张这只是一个判断浏览器的函数,你可以使用很多方法来判断浏览器
    var ua=navigator.userAgent.toLowerCase(),sys={};
    sys.firefox
    =ua.match(/firefox\/([\d\.]+)/);
    sys.ie=ua.match(/msie\s([\d\.]+)/);
    sys.chrome
    =ua.match(/chrome\/([\d\.]+)/);
    return sys;
    })(),
    $j
    =function(id){return document.getElementById(id);},
    imgall
    =$j('aaa').getElementsByTagName('DIV'),
    getoff
    =function(o){//获取IMG对象的 offw and offh
    //alert(o.width)
    o.innerHTML=(o.offsetTop-warpper.offsetTop) +','+ (o.offsetLeft-warpper.offsetLeft);
    return (o.offsetTop-warpper.offsetTop) +','+ (o.offsetLeft-warpper.offsetLeft);
    //注意 o.offsetTop 在chrome下要等window.onload以后才能正确获取
    };
    //o.offsetTop获取对象距离浏览器顶部的距离 必须减去外面容器的距离浏览器的距离。(如果使用window容器就不用了)

    (
    function(){//初始化容器对象绑定事件==
    if(wf){
    window.onscroll
    =function(){_this.judge();};
    window.onresize
    =function(){_this.judge();};
    }
    else{
    warpper.onscroll
    =function(){_this.judge();}
    warpper.onresize
    =function(){_this.judge();}
    }
    window.onload
    =function(){setTimeout(_this.judge,500);};
    })()
    //容器对象设置结束

    for( i ; i<imgall.length ; i++ ){//初始化imgs 数组
    var arr=[],off;
    off
    =getoff(imgall[i]);
    //alert(off)
    arr.push(imgsurl[0]);
    arr.push((off.split(
    ',')[0]));
    arr.push((off.split(
    ',')[1]));
    imgs.push(arr);
    }

    _this.Load
    =function(){
    var hereline=[];
    hereline[
    1]=doc.offh+doc.jtop;
    hereline[
    2]=doc.offw+doc.jleft;

    for(i=0;i<imgs.length;i++){

    if(imgs[i][1] != undefined){//判断当前对象是否已经加载过
    var jj=hereline[1] - imgs[i][1] < doc.offh +130 && hereline[1] - imgs[i][1] > 0 ? true : false,
    jjj
    =hereline[2] - imgs[i][2] < doc.offw +270 && hereline[2] - imgs[i][2] > 0 ? true : false;
    if(jj && jjj){
    imgall[i].innerHTML
    +=''+(++j)+'个加载';
    imgs[i][
    1]=undefined;
    }
    }

    }

    if( j >= imgs.length){//判断是否已经全部加载完毕
    //取消时间绑定
    alert("已经全部加载完成,程序将不再执行")
    warpper.onscroll
    =null;
    warpper.onresize
    =null;
    }
    }



    _this.docInfo
    =function(){//获取容器的相关信息
    var d={},db= (wf)? document.body : warpper,
    dd
    =(wf) ? document.documentElement : warpper;
    if(sys.ie){
    d.offh
    =dd.offsetHeight;//可视区域H
    d.offw=dd.offsetWidth;//可视区域W
    }else{
    if(wf){
    d.offw
    =window.innerWidth;//可视区域H
    d.offh=window.innerHeight;//可视区域W
    }else{
    d.offh
    =dd.offsetHeight;//可视区域H
    d.offw=dd.offsetWidth;//可视区域W
    }
    }
    d.jtop
    =(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
    d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft : db.scrollLeft;//水平卷去宽度
    //被卷去的宽度 window 使用两个相加 div的卷曲就直接使用scrollLeft就OK
    $j("bbb").innerHTML=d.offh+','+d.offw+','+d.jtop+','+d.jleft
    return d;
    }
    //注意在非IE 浏览器下 获取非window对象的可视区域 使用offsetHeight 和 offsetWidth (跟IE 一样)
    //在非IE 下获取 window对象的可视区域 则要使用 window.innerWidth 和window.innerHeight
    //也就是说在非IE 下的 window 和 非window 对象的 可视区域获取是不一样的。

    _this.judge
    =function(){//后来发现不用判断方向了
    var d=_this.docInfo();
    if( d.jtop != doc.jtop || d.jleft != doc.jleft || d.offw > doc.offw || d.offh > doc.offh){
    //判断是否需要执行加载
    //条件为 被卷去的 y x 变化 或者 窗口大小 发生变化触发
    doc.jtop = d.jtop;
    doc.offh
    = d.offh;
    doc.jleft
    = d.jleft;
    doc.offw
    = d.offw;
    _this.Load();
    //加载程序
    }
    }
    //setTimeout(_this.judge,500);//执行初始化加载
    //setTimeout 防止onload 和 onscroll的重复执行
    //也就是本来就有onscroll的时候 最先执行了onload
    return _this;

    }

    })()
    lazyload();
    </script>


    </body>
    </html>
  • 相关阅读:
    《 动态规划_ 货币系统 》
    《动态规划_入门 LIS 问题 》
    数据库中左连接、右连接、全连接的区别
    http和https的区别与联系
    【复习周之流水账记录】
    web前端整套面试题(三)--网易的面试题
    微信小程序相关三、css写小黄人
    CSS选择器的匹配规则
    web前端整套面试题(二)--今日头条面试题
    有趣的逻辑题
  • 原文地址:https://www.cnblogs.com/idche/p/lazyload.html
Copyright © 2011-2022 走看看