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 说:

    淡淡的发

  10. Sunhoo 说:

    感谢楼主分享,但是Demo在苹果Ipod Touch5上浏览会出现加载延时或加载很慢。这个有办法解决吗?

  11. 一月 说:

    非常感谢您的分享;我用的demo1,但我发现一个问题,图片是100个随机排序的,但我只有20个图片,所以当20以后的图片排在前边的时候,就是一片空白;请问怎么定这个数量呀?我的QQ邮箱928961201@qq.com,非常期待您的回复,谢谢

  12. 浪子啊 说:

    晕,只要有一张图片链接出错,就整个全挂。。。

  13. 不錯啊很好玩的樣子取

  14. chaxilliava 说:

    #:-o – 00 98920

  15. hgh 说:

    楼主 我这发现一个问题好像 比如 浏览器滑块滑动 底部只有一个图片的时候 但不滑到底部 可以看到这张图的左右 都空白 知道浏览器完全显示这张图片的时候 才开始加载下面的内容
    569457128@qq.com  期待回复 O(∩_∩)O谢谢

  16. 梦罗兰 说:

    愿主与你同在,每天充满喜乐!

  17. 猪猪家的 说:

    LL  方便发邮箱一份吗 如果能够翻页就万分感谢了哦 734307571@qq.com  谢谢LL

  18. 嬗变 说:

    楼主,我自己用thinkphp写了一个瀑布流形式,不过有些问题我解决不了,怎么可以和你联系,我把我代码发出来,您帮我看一下?可以发邮件给我

  19.  
    http://www.tmeng.cn/video.html
    就是我们这个瀑布流 一打开页面时,图片漂浮起来
    拖快了,也漂浮起来 !
    只有IE下这样,其他浏览器正常。
    能帮忙看下吗?谢谢
    Q:243166055

  20. SV 说:

    请问demo1和demo2过渡的效果不同,是不是因为demo1是事先加载好的图片,网页打开定位后有一个过渡效果;demo2的图片是动态加载的,加载后会直接定位,这样显示的位置就是定位后的位置,所以不会有移动的过渡效果,是不是这个原因?

    • leon 说:

      嗯嗯。你说的很对!如果想要demo2也有那种散开的效果,就要在图片加载之后先给一个初始位置:left:0;top:当前最左栏的高度。所有图片都加载完毕之后再给出各自的最终位置,再用css写过渡效果就ok啦~经测试过渡曲线ease-in-out的体验是最优雅的

      • SV 说:

        谢谢楼主的回复。前两天我改了一下代码,动态加载时也可以有demo1的效果了,但是第一次加载时定位函数不执行,有点奇怪,改天有时间我再看看。

  21. SV 说:

    请问如何让demo2排列的时候是demo1的过渡效果?

  22. MV下载 说:

    DEMO 的文件貌似有点问题。。。。

  23. lsac1999 说:

    能重新分享下demo吗?两个连接都失效了。

  24. 微趣 说:

    一直在弄瀑布流  , 感谢。

  25. 水手 说:

    楼主, 你的源码地址是空链接,能给发我邮箱不?谢谢楼主!ouyangtao404@qq.com

  26. tamik 说:

    下载不了,,链接无效。。。

  27. ccc 说:

    求个 固定高度 横向 瀑布布局  思路写法 谢谢

  28. 呼噜 说:

    加载到一定高度就翻页 怎么实现

    • leon 说:

      可以用数量来控制,比如加载了1000张图片后就翻页。翻页后的查询可以用get参数来控制

  29. […] 额,这篇文章是从迅雷CUED博客转过来的,虽然那篇也是我写的,国际惯例给个链接吧…… […]

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

  31. abc 说:

    都下载不了

  32. […] http://cued.xunlei.com/log031 此条目由 admin 发表在 JavaScript 分类目录,并贴了 JQuery、前端、瀑布流 标签。将固定链接加入收藏夹。 […]

  33. Lewis 说:

     
    我也针对人人逛街的数据,写了一个商品和图片的瀑布流,不过是基于 float :left 方式写的,同样可以适应各种屏幕布局,欢迎朋友使用。
     
    http://www.jsbug.com/tools/wall/
     

  34. 你好,想请问一下,如何限制每行栏目的多少,现在的是默认5个如果是4个是修改哪个 菜鸟 哈。找了半天CSS

  35. kedison 说:

    你好, 我想知道json.php怎么能丛dedecms里获取文章数据呢?

    • 阿牛 说:

      我的网站是用http://www.m8v8.com/dedecms做的瀑布流,是用的另外的一个JS插件不过不能实施延迟加载,但是我的图片高度都是用程序输出的,找了很久也不知道哪里出问题了

      • kedison 说:

        高度我就知道怎么搞, 我现在就是想知道怎么无限加载, 看不出有什么问题呀?

    • xwei 说:

      看看它的表结构,然后写SQL取需要的数据即可

  36. 路人甲 说:

    IE7下貌似也有点小小的问题。就是第一次加载的时候。图片位置变化会很大。之后就ok

  37. 路人甲 说:

    貌似是有dome3在FF下好像是有问题哦。网页会滚到最下边。然后一直请求一直请求。。FF的版本13.0.1

    • leon 说:

      FF这个BUG确实奇葩,刷新10次偶尔会出现一次,看来只能设置ajax间隔时间了

  38. sakura 说:

    根本就不能下载啊,

  39. 尛何 说:

    太有才了!

  40. Gareth 说:

    能实现某些内容置顶显示吗

  41. happTIME_2 说:

    这个必须顶起!!!话说为什么评论没表情提供!!!!!!!!!!!!!!!!!!

  42. peter2012 说:

    你好!我下载了您提供的程序包,但是无法直接运行。点击demo2.html后页面上只有“正在加载…”字样,但是运行您提供的链接页面是成功的。这个需要什么特殊的配置吗?多谢!

  43. […] 今天四处闲逛,看到迅雷UEDxwei兄写了篇名为“浅谈个人在瀑布流网页的实现中遇到的问题和解决方法(http://cued.xunlei.com/log031)”的文章,我两只沉沉的萝卜眼顿时放出无数闪亮的小星星。 […]

  44. qq1196 说:

    哥们,你这个对浏览器兼容性好像有问题,

  45. amei 说:

    你好,强大,学习了。
    想问一下,如何让图片链接到img/big/下的相应大图?
    我想融合一下lightbox效果进去

  46. 新学期 说:

    太好了,多谢,把之前的问题解决了,感谢

  47. 南京SEO 说:

    果断收藏了

  48. 山楂布丁 说:

    本人半拉子都算不上,一直没明白数据如何传入,即如何与后端集成。
    毕竟实际使用数据可都是来源于数据的

  49. 博主写的东西确实不错,赞~~~

  50. 已经到你这儿几次了,第一次留言。很喜欢你的文章。希望能和博主交个朋友!

  51. o2o 说:

    这个很有学习的价值,不错~

  52. 检讨书 说:

    博主的文章很不错,经常来光顾。希望能看到更好的文章。欢迎回访!

  53. 推闻 说:

    想学习下WP7 把前几个格子弄成动态,这些估计要用什么方式实现呢?

  54. 初七 说:

    太好了! 无情地收藏了!

  55. 好文章,不错,收了

  56. 第一次来你这,支持下,以后会常来!期待你的博客越来越好

  57. 很不错,学习了

  58. ygm125 说:

    用了http://cued.xunlei.com/demos/publ/img/P_039.jpg这个测试 结果是一样的啊

  59. 来看看 说:

    老大,能不能把php也贴出来看一下呀,好了解一下

  60. mianu 说:

    瀑布流+无限拖怎么实现

  61. WAWA 说:

    学习了。。。

  62. zouhao 说:

    酷~

  63. 小人 说:

    “ imgs=el.getElementsByTagName("img");//只遍历新增图片 ”
    这句其实并没有只遍历新图片啊~~~~~~~~~~~~还是所有图片都遍历一次~~~~
    也就是无限拖后这个imgs.length会很大~是吗?

    • xwei 说:

      只遍历新图片的算法在下面,我注释位置错误了 呵呵
       

      for(i=sumChild;i<imgs.length;i++){
            var img = new SImage(icall,el,imgs.length,imgs[i].src,newBox);
      }
      img是数组,存放所有图片
      sumChild是ajax请求之前格子的总数,也就是从数组的第sumChild个元素开始遍历,判断是否加载完毕。

      至于遍历所有img节点来取出数组确实效率有些低,无限拖之后这个数组也会无限大,这里也考虑换用id选择器。

      PS:imgs.length是指?数组的大小?

       

      • 小人 说:

        多谢回复…..对的….就是这个问题……其他都很完美…
        “至于遍历所有img节点来取出数组确实效率有些低,无限拖之后这个数组也会无限大,这里也考虑换用id选择器”………
        无限拖后…这个imgs.length这个图片数量会越来越多…..每次onscroll都遍历一遍所有图片….太消耗了
        如果这个imgs.length是指新插入图片的数量就完美了…
         
         

  64. 小八戒 说:

    不错,就想学习瀑布流的布局,还有一些web前端的技术

  65. 易车居 说:

    支持UED团队,很多值得学习的东西!

  66. wk673w 说:

    千年等一回的好帖

  67. 誓言 说:

    json.php 的代码可以提供么?

  68. kim 说:

    感谢分享。

  69. xiaoqiang 说:

    感谢楼主分享,最近也在研究。
    对于获取高度问题。我记得看过一个文章,可以利用浏览器来获取图片文件头,从而实现在图片刚开始加载的时候就拿到图片的高宽,同时还附了一个demo,效果还不错。回头找找去。

  70. 榴莲好吃 说:

    喔!顶!!!!

  71. A的世界 说:

    思路非常好  但是 代码是JS生成的不利SEO 优化
     

    • xwei 说:

      是啊,ajax一度被称为搜索引擎杀手,对这个问题前端很难有什么好办法,实际项目中只有结合后端技术来解决了

  72. […] 好了,以上就是在这次瀑布流实现过程中遇到的问题和解决方法,由一开始加载3-4屏就卡死到现在可以无限加载(ff,chrome),深感优化js的必要性和无限性。一点小心得写在这里权当抛砖引玉,大家对瀑布流实现的优化有什么见解欢迎一起交流讨论。(来源:迅雷CUED) 本文标签: 布局,设计 本文链接: 浅谈瀑布流网页实现中遇到的问题和解决方法 版权所有: 除非注明,文章均为蓝枫博客原创,转载请注明出处及链接! 订阅更新: 您可以 订阅我们 的内容更新或者 分享给更多的朋友 上一篇: 时尚电商modaoperandi: 预售六个月后的时尚 […]

  73. 书生 说:

    哦!对了!谢谢xwei 技术分享!O(∩_∩)O谢谢!

  74. 书生 说:

    晕!3个小时了!涉及的算法有点多,不研究了!后面有空慢慢来吧!看样子该睡觉了!瀑布流。。。。。今天刚接触!看样子我的站点很有用啊!呵呵!

    • xwei 说:

      嘿嘿,感谢书生兄的提点,事实上我之前用了php的getimagesize函数来获取图片大小,但是尺寸的误差非常大。如果服务器可以给出图片大小的话(实际项目中可以考虑在图片上传的时候保存宽高到数据库中),ajax的请求返回值从高到低排序是非常合理的。感谢~

    • 小八戒 说:

      慢慢来啊。瀑布流

  75. 书生 说:

    ⊙﹏⊙b汗!!才发现原来列不是固定的。这样的话,也可以优化一下下面的问题:
    服务器发回来的图片进行由高到低排序,然后取前N(列数)个,实现把最高的图片放到列数里面最低的一个里面,第二高放到第二低里面,依次类推。。。。。。,然后再取N个重复上面的步骤,直到这15个图片都排完。(只要是列的倍数就行,我看您们的效果了,我点了点是每次15个)。这样15个排完会减少出现高的列比矮的列高出很多,空白很大等问题。
     
     

  76. 书生 说:

    提一点小小的建议:1     2      3         4      5  列   列数是固定的了位置也固定了,
    服务器发回来的图片进行由高到低排序,然后取前N(列数)个,实现把最高的图片放到列数里面最低的一个里面,第二高放到第二低里面,依次类推。。。。。。,然后再取N个重复上面的步骤,直到这15个图片都排完。(只要是列的倍数就行,我看您们的效果了,我点了点是每次15个)。这样15个排完会减少出现高的列比矮的列高出很多,空白很大等问题。 顺便问一下可不可以交换一下友情链接啊?不做也没事的。只是问一下。这是我的第一个站。欢迎在我的站点意见反馈里面提建议!

  77. 思密达 说:

    最近很流行,收藏了。

  78. 书生 说:

    学习了!慢慢看!先占个沙发!

发表你的评论