CUED-迅雷用户体验设计中心

浅谈个人在瀑布流网页的实现中遇到的问题和解决方法

先上Demo

瀑布流排序 : http://cued.xunlei.com/demos/publ/demo1.php

瀑布流+无限拖  http://cued.xunlei.com/demos/publ/demo2.html

瀑布流+无限拖 (js获取图片高度版)  http://cued.xunlei.com/demos/publ/demo3.html

补充说明:因为之前的图片命名规则过于简单,容易被盗链啥的,被管理员发现。所以用php的Mcrypt函数库加密了一下图片名称。json.php获取图片的算法也做了一些修改 (当然为了保证已经远程调用我们图片的站点能够正常打开,原图是保留的,老客户请放心使用~另外加密算法很简单,DES+凯撒2层,有兴趣的同学可以破解一下,密钥提示:每天的图片名称都不同哦~)

为了方便大家本地调试程序,现将过去版本打包,下载地址:

迅雷方舟下载猛击这里

迅雷快传下载狂按这里

随着pinterest的走红,瀑布流式的布局被越来越多的网站所使用,这种布局确实有很多好处,图片列表页有很强大的视觉感染力,而且还提高了用户“发现好图”的效率。瀑布流的实现有很多种方式,之前淘宝UED有篇文章详细的介绍过各种方式的优劣。今天我们主要讨论一下绝对排序来实现瀑布流的方式 即 Pinterest 采用的方式。

首先说下瀑布流的排序算法,参考demo1,思路非常简单,我们把瀑布流拆成三个部分来看:容器、列、格子

1.先计算当前屏幕最多能容纳几列瀑布,其值为 "向下取整(屏幕可见区域宽度/(格子宽度+间距))";

2.为了保证容器的居中,将容器的宽度设置为 列数* (格子宽度+间距) – 间距,这里需要注意的是 当容器的宽度计算出来之后再显示,否则会造成页面宽度的抖动,影响体验。;

3.排序开始,先把前N(N为列数)个格子分别放到每一列中,然后每次寻找高度最小的一列,把格子放进去(left值为列序号*(格子宽度+间距),top值为 列高+间距),并刷新列的高度,遍历所有格子直到所有的格子都被排序。
 

最后将事件句柄绑定到window.onload和window.onresize上,一个瀑布流布局的页面就出来了。

 

 

这样的排序算法看起来很美好,可真正结合异步加载数据应用到页面里还要解决以下几个问题

1.当缩放浏览器窗口时会不断地触发事件,如果每次都响应的话会狂耗性能,需要在缩放动作结束后再执行重排方法。

2.页面滚动到底部请求数据成功之后只对新增的节点重排。

3.如果服务器无法给出图片高度,需要在图片加载完毕之后再进行重排。

 

第一个问题我是用setTimeout和clearTimeout来解决的,思路是窗口变化之后开始计时,如果窗口还在变换则从新开始计时,窗口不再变化则延时(很短的时间)触发重排事件。暂时只想到这个,这里应该还有更好的方法。
代码如下

var re;
window.onresize = function() {
    clearTimeout(re);
    re = setTimeout(resize,100);
};

 

第二个问题在于如果每次有新的数据加载,都要对整个容器内的节点进行重排,非常消耗性能。解决思路:

1.将列保存在全局数组中,每次重排或者新增格子之后更新数组的数据,这样下次执行排序算法的时候可以直接调用。
2.将新增格子保存在数组中作为参数传递给排序算法,仅对新格子进行遍历和操作。

第三个问题是如果服务器无法给出图片尺寸,那么必须在图片完全加载完毕之后才可进行排序(因为高度是实时获取的,图片不全高度有误差),这里没有什么好办法,只能遍历图片,每张图片加载成功后执行一个回调函数,将加载成功的图片数量+1,当加载成功的图片数量等于图片总数的时候执行排序方法。缺点是有一张图片加载不成功就无法看到所有的,真正项目中还是需要在异步加载数据的时候获取图片尺寸。

好了,以上就是在这次瀑布流实现过程中遇到的问题和解决方法,由一开始加载3-4屏就卡死到现在可以无限加载(ff,chrome),深感优化js的必要性和无限性。一点小心得写在这里权当抛砖引玉,大家对瀑布流实现的优化有什么见解欢迎一起交流讨论。

 

PS:一点视觉上的优化,如果服务器可以给出图片尺寸的话,返回的json字符串应该是按照高度从高到低排序的,这样可以使瀑布流底部尽量持平(感谢书生的指点)。

PS2:感谢 xiaoqiang 的分享,demo3中使用了通过文件头信息获取尺寸的方法,格子在图片加载完毕之前就可以完成排序,但是那个方法在ie下获取的头信息有些误差,不知道问题出在哪里?望高手指点

PS3:抛砖引玉的目的达到了,这么多人一起思考和讨论,让这个瀑布流越来越快啦~潜水的高手们该出手了

应观众要求贴出php代码,其中用了2种方式试图获取图片高度,均不准确

<?php
$num = $_POST["num"]; //获取加载数量
$t = "{images :["; //构建json字符串
for($i=0;$i<($num-1);$i++)
{
  $src=rand(1,84);
  $src=(string)$src;
  if(strlen($src)  == 1) {$src = "00" . $src;}
  else if(strlen($src) == 2) {$src = "0" . $src;} //处理随机字符串
  $img = imagecreatefromjpeg("img/P_".$src.".jpg");//PHP生成图片
  $arr = imagesy($img);//获取图片高度(失败)
  $t = $t."{src : $src,height:$arr},";
}
  $src=rand(1,84);
  $src=(string)$src;
  if(strlen($src)  == 1) {$src = "00" . $src;}
  else if(strlen($src) == 2) {$src = "0" . $src;}
  $arr = getimagesize("img/P_".$src.".jpg"); //php获取图片信息(失败)
  $t=$t."{src : $src,height:$arr[1]}]}";
  echo $t;
?>

另外截图贴出那个用头信息获取高度的代码在IE下的奇怪效果,chrome的正常尺寸:

IE8下

望高手指点……

  1. […] 浅谈个人在瀑布流网页的实现中遇到的问题和解决方法 […]

  2. 你好,您的DEMO链接已经失效可以传一份给我吗邮箱407593529@qq.com 跪谢了找了好久没找到合适的
    另还想请教一个问题瀑布流挤到一起了是怎么回事呢http://www.ruoshuiyx.com/case/case_1.html
    在谷歌浏览器里打开后刷新就挤到一起了,纠结了半年了没解决不知道哪里的问题

  3. wayne、 说:

    楼主..你的下载链接是空的呀.能发个给我吗? 284419347@qq.com
    这几天正好在研究瀑布流.

  4. xhrno13 说:

    兄弟,你给的链接都下载不了,请你发一份demo的源文件给我行吗?万分感谢!
    邮箱:xuhaoranlj@163.com

  5. bestchao 说:

    发现两个问题,第一个问题,在IE下ajax加载完成的图片会再次变换。第二个问题,#wrap div样式直接写给.mode,然后在其mode容器内再加DIV,IE会出现兼容问题

  6. zjmean 说:

    兄弟,你给的两个网址都无效了。能不能劳烦您给我邮箱发一份源码呢。
    万分感谢啦
    zjmean@163.com

  7. 小欣 说:

    o(︶︿︶)o 唉 下载不来了~

  8. […] 浅谈个人在瀑布流网页的实现中遇到的问题和解决方法 xwei | 2012-03-21 18:18  | 网页重构 […]

  9. q285661571 说:

    淡淡的发

    • q285661571 说:

      呃 发错了 demo1没问题 demo2 demo3下载后 本地打开没有图片显示,只有“正在加载….”