zoukankan      html  css  js  c++  java
  • 重构项目之二:使用瀑布流效果加载图片

    虽然这个功能最后使用了另外的插件,但是还是讲一下大概的原理吧,还是先上图:

    功能描述:

      1. 根据不同菜单的属性值分别加载不同的数据

      2. 下拉滚动条到一定位置预加载图片,滚动条拉到最底下的时候渲染html;

      3. 鼠标移到菜单,切换各个图片列表;

      4. 鼠标移到图片列表上,显示详细信息;

    技术实现方案:

      先梳理一下从加载到显示的流程:

      1. 加载数据
      2. 拼接HTML写入到页面
      3. 检查刚刚写入的HTML中的img是否全部加载完成,如果是,进入5、否则进入4
      4. 等待图片加载完成
      5. 计算每个元素的位置

    一开始的时候最头疼的是如何定位的问题,后来经过朋友指导终于解决:

      计算总共有多少列图片并且把每一列的高度都放到一个数组里面。每当一张图片加载完成的时候就查找这个数组里面最小的值,并且定位当前图片的top设置为这个值,完成后把这个图片的高度加上数组里面的最小值并且返回到数组里面,依次类推。 

    PS:因为这个功能代码太多,只能作基本的简单分解代码了: 

     1 // 创建用于记录每列高度的数组
     2 _getLowestCol: function() {
     3     t._cols = new Array(5),min = 0;
     4     // 初始化为0
     5     for (var i = 0; i < t._cols.length; i++) {
     6         if (cols[i] < cols[min]) {
     7             min = i;
     8         }
     9         return min;
    10     }
    11 },
    12 _reposition: function() {
    13     t._grids.each(function(i, grid) {
    14         //先显示出来
    15         grid = $(grid).show();
    16         
    17         var height = grid.outerHeight(), min = t._getLowestCol();
    18 
    19         // 定位
    20         grid.animate({
    21             left: (t._colWidth + t._colSpacing) * min,
    22             top: t._cols[min],
    23             opacity: 1
    24         },1000);
    25         // 记录高度
    26         t._cols[min] += height;
    27     });
    28 
    29 }
    View Code

    其次开发过程中遇到的难题是:

      因为如上图所示,鼠标移动到菜单栏需要切换图片列表,并且分别需要用瀑布流加载不同类型的数据。所以要处理在切换页面的时候如何才能做到每个页面只执行一次代码请求接口,而不需要每一次切换都重新请求数据接口,仅仅执行切换显示图片列表的操作就可以了。

      考虑到每一个菜单都有一个自定义属性,所以这个问题轻易地解决了:建立一个对象来记录当前菜单是否已经执行过代码,如果没有就执行请求数据 。 

     1 var isLoad = {};//是否载入过
     2 labelType.mouseover(function() {
     3     var i = $(this).index();
     4     var api = _this.attr('api');//接口标识
     5     
     6     if(! isLoad[ api ]){
     7         isLoad[ api ] = i;
     8         loadData(wrapper, api);
     9     }
    10     
    11 });
    View Code

    以下为全部代码:

    html:

     1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     5 <title></title>
     6 <style type="text/css">
     7 *{margin:0;padding:0;}
     8 ul,li{    list-style-type:none;}
     9 li img{width:100%;list-style:none;}
    10 </style>
    11 </head>
    12 <body>
    13     <div class="photo_box">
    14         <ul id="container" style="border:1px solid #000;80%;height:600px;overflow:hidden;margin:0 auto;position: relative;">
    15         </ul>
    16         <div id="loading" class="loading" style="text-align: center;margin-top: 20px;font-size: 1.2em;">加载中...</div>
    17         <div id="more" class="more"style="text-align: center;margin-top: 20px;font-size: 1.2em;"><input type="button" value="更 多" id="clear" /></div>
    18     </div>
    19 <script type="text/javascript" src="http://daisy.com/js-learning/resule/_example/waterFall_1.2/waterfall.js"></script>
    20 <script type="text/javascript" src="http://x1.xiuimg.com/webjs/lib/jquery/jquery/1.7.2/jquery.js"></script>
    21 <script type="text/javascript">
    22 
    23     waterFall.init({
    24         container: $('#container'),
    25         dataURL: 'http://www.woxiu.com/index.php?action=Index/Main&do=ApiZhuboGrade',
    26         dataType: 'jsonp',
    27         colWidth: 200,
    28         colSpacing: 10,
    29         rowSpacing: 15,
    30         page: 1,
    31         pageEnd: 8,
    32     });
    33 
    34     // 限制同时展示的页数
    35     var loadCounter = 1;
    36     function pageNum(){
    37         if (loadCounter >= 3) {
    38             $('#more').show();
    39             $('#loading').hide();
    40             return true;
    41         } else {
    42             loadCounter++;
    43             $('#more').hide();
    44             $('#loading').show();
    45         }
    46         return false;
    47     }
    48     $('#clear').click(function() {
    49         loadCounter = 1;
    50         waterFall._loadNext();
    51     });
    52 
    53 
    54 </script>
    55 </body>
    View Code

    js:

      1 /**
      2  * 瀑布流布局组件类
      3  * @param {Object} options 组件设置
      4  *        @param {NodeList} options.container 瀑布流容器
      5  *        @param {String} options.dataURL 数据地址
      6  *        @param {String} [options.dataType='jsonp'] 数据类型,json或jsonp
      7  *        @param {String}    options.template 模板编辑
      8  *        @param {Number} [options.colWidth] 图片大小。
      9  *        @param {Number} [options.colSpacing] 列间隔。
     10  *        @param {Number} [options.rowSpacing] 行间隔。
     11  *        @param {Number} [options.page=1] 数据开始页码
     12  *        @param {Number} [options.pageEnd] 数据末尾页码
     13 
     14  * @pageNum() 函数,如果不需要现在加载也是,需要把函数里面的判断去掉。
     15 
     16 
     17  从加载到显示的流程
     18 
     19 1. 加载数据
     20 2. 拼接HTML写入到页面
     21 3. 检查刚刚写入的HTML中的img是否全部加载完成,如果是,进入5、否则进入4
     22 4. 等待图片加载完成
     23 5. 计算每个元素的位置
     24 
     25  */
     26 
     27 
     28 var waterFall = {
     29     init: function(options) {
     30         var t = this;
     31         t._container = options.container;
     32         t._colWidth = options.colWidth;
     33         t._colSpacing = options.colSpacing;
     34         t._rowSpacing = options.rowSpacing;
     35         t.dataURL = options.dataURL;
     36         t.dataType = options.dataType;
     37         t.page = options.page;
     38         t.pageEnd = options.pageEnd;
     39         t._switch = false;
     40 
     41         //计算有几列 总宽度 / (列宽 + 列间隔)
     42         t._totalCols = parseInt(t._container.width() / (t._colWidth + t._colSpacing));
     43 
     44         // 创建用于记录每列高度的数组
     45         t._cols = new Array(t._totalCols);
     46         // 初始化为0
     47         for (var i = 0; i < t._cols.length; i++) {
     48             t._cols[i] = 0;
     49         }
     50 
     51         t._loadingPage = options.page || 0;
     52         t._loadNext(options);
     53 
     54         //下拉滚动条加载
     55         var lastTime = new Date().getTime();
     56 
     57         $(window).scroll(function() {
     58 
     59             if ( !t._switch ) {
     60                 //判断是否滚动过快,在ie下
     61                 var thisTime = new Date().getTime();
     62 
     63                 if (thisTime - lastTime < 50) {
     64                     console.log(thisTime - lastTime);
     65                     lastTime = thisTime;
     66                     return;
     67                 }
     68 
     69                 if ($(window).scrollTop() + $(window).height() >= document.documentElement.scrollHeight) {
     70                     lastTime = thisTime;
     71                     t._loadNext();
     72                 }
     73             }
     74         });
     75     },
     76     //加载器
     77     _loadNext: function(t) {
     78         var t = this;
     79 
     80         t._switch = true;
     81         //请求数据
     82         if (!t.trigger) {
     83             $.ajax({
     84                 url: t.dataURL,
     85                 data: { page: ++t._loadingPage },
     86                 dataType:t.dataType,
     87                 success: function(response){
     88                     
     89                     t.trigger = t._completeLoading(response);
     90 
     91                 },
     92                 error:function(){console.log('Error! 请求有误');}
     93             });    
     94         }
     95         return false;
     96     },
     97     //加载完数据调用此函数
     98     _completeLoading: function(result) {
     99         var t = this;
    100         if (t._loadingPage >= t.pageEnd) {
    101             $('#more').hide();
    102             $('#loading').html('<p>已是最后一页了喔 ^_^ ^_^</p>');
    103             return true;
    104         }
    105         else {
    106             //if (!pageNum()) {
    107                 t._add(result);
    108             //};
    109         }
    110         
    111         return false;
    112     },
    113     //添加格子
    114     _add: function(result) {
    115         var t = this, grids = '';
    116         var content = '';
    117         for(var i = 0; i < 10; i++) {
    118             content += '<li style="display: none;">' +
    119                 '<img src = "http://tse1.mm.bing.net/th?id=OIP.Md8a5117c45764bb6064156cc2f08a5f4o0&w=135&h=272&c=7&rs=1&qlt=90&o=4&pid=1.9">' +
    120             '</li>';
    121         }
    122 
    123         console.log(content);
    124         //原始定位
    125             t._grids = $(content).css({
    126                 position: 'absolute',
    127                 left: t._container.width(),
    128                 top: t._container.height(), 
    129                  t._colWidth,
    130                 opacity: 0
    131             });
    132 
    133         //把Html添加到容器
    134         t._container.append(t._grids);
    135 
    136         // 执行一次_reposition,如果所有图片都加载完成,该方法返回true,否则返回false
    137         if ( !t._reposition() ) {
    138             // 有图片未加载完,监听onload和onerror
    139             t._grids.find('img').bind('load error', function() {
    140                 this.loaded = true;
    141                 // 有图片加载完成,再次执行_reposition
    142                 if (t._grids) {
    143                     t._reposition();
    144                 }
    145             });
    146         }
    147     },
    148     // 此方法用于获取高度最低的列
    149     _getLowestCol: function() {
    150         var cols = this._cols, min = 0;
    151         for (var i = 1; i < cols.length; i++) {
    152             if (cols[i] < cols[min]) {
    153                 min = i;
    154             }
    155         }
    156         return min;
    157     },
    158     //定位
    159     _reposition: function() {
    160 
    161         var t = this, allImgsLoaded = true;
    162 
    163         // 检测图片是否全部加载完成
    164         t._grids.find('img').each(function(i, img) {
    165             if (!img.loaded && !img.complete) {
    166 
    167                 allImgsLoaded = false;
    168             }
    169             return allImgsLoaded;
    170         });
    171 
    172         if (allImgsLoaded) {
    173             t._grids.each(function(i, grid) {
    174                 //先显示出来
    175                 grid = $(grid).show();
    176                 
    177                 var height = grid.outerHeight(), min = t._getLowestCol();
    178 
    179                 // 非第一行的时候,要加上行间隔
    180                 if (t._cols[min]) { t._cols[min] += t._rowSpacing; }
    181                 // 定位
    182                 grid.animate({
    183                     left: (t._colWidth + t._colSpacing) * min,
    184                     top: t._cols[min],
    185                     opacity: 1
    186                 },1000);
    187                 // 记录高度
    188                 t._cols[min] += height;
    189             });
    190             // 重设外层容器高度为最高列高度
    191             t._container.css( 'height', Math.max.apply(Math, t._cols) );
    192             t._switch = false;
    193             delete t._grids;
    194         }
    195 
    196         return allImgsLoaded;
    197     },
    198 }
    View Code

    PS:欢迎来我秀欣赏美女直播喔(*^__^*) :http://www.woxiu.com/

    【全都是流水账,仅仅记录进步的点滴】
  • 相关阅读:
    SAP Tax Service可以取代TAXBRA / RVABRA吗?(翻译) 跨国贸易云税务解决方案
    SAP Brazil J1BTAX 为税收例外创建税收组(翻译)
    WordPress 安装插件导致 HTTP 500 内部服务器错误的问题
    12 Best Live Chat Software for Small Business Compared (2019) 最佳的wordpress在线聊天工具推荐插件 来帮你和潜在客户互动
    一个虚拟主机或空间实现放多个网站的方法【非常实用】
    用WordPress建立专业网站教程 (一步步建站, 一步也不少)
    阿里云+wordpress搭建个人博客网站【小白专用的图文教程】- 【转发】 AWS云和WordPress搭建个人博客网站
    【原创】SAP/Oracle 集团企业海外全球化实施注意事项: 一带一路本地化 (持续更新)
    AI人工智能顶级实战工程师 课程大纲
    联想项目结束了,聊聊华为SAP HANA项目八卦
  • 原文地址:https://www.cnblogs.com/Travel/p/4463820.html
Copyright © 2011-2022 走看看