瀑布流布局(基于多栏列表流体布局实现)

转在前面:(淘宝UED)

3) 绝对定位。即 Pinterest ,Mark之,KISSY 采用的方式:
瀑布流布局(基于多栏列表流体布局实现)

  • 可谓是最优的一种方案,方便添加数据内容,窗口变化,列数/数据块都会自动调整;
  • 线上例子。

缺点:

  • 需要实现知道数据块高度,如果其中包含图片,需要知道图片高度;
  • JS 动态计算数据块位置,当窗口缩放频繁,可能会狂耗性能。

KISSY.Waterfall 实现思路

KISSY 的 Waterfall 组件主要包含两个部分,一个是对现有数据块进行排列计算各自所在的位置; 二是下拉滚动时,触发加载数据操作,并把数据添加到目标容器中。

1) 数据块排列,算法步骤简述下:

  • 初始化时,对容器中已有数据块元素进行第一次计算,需要用户给定: a,容器元素 — 以此获取容器总宽度; b,列宽度; c,最小列数; 最终列数取的是容器宽度/列宽度和最小列数的最大值,这样保证了,当窗口很小时,仍然出现最小列数的数据;
  • 获得列数后,需要保存每个列的当前高度,这样在添加每个数据块时,才知道起始高度是多少;
  • 依次取容器中的所有数据块,先寻找当前高度最小的某列,之后根据列序号,确定数据块的left,top值,left 为所在列的序号乘以列宽,top 为所在列的当前高度,最后更新所在列的当前高度加上这个数据块元素的高度,至此,插入一个元素结束;
  • 当所有元素插入完毕后,调整容器的高度为各列最大的高度值,结束依次调整;
  • 性能效率上的注意点: a,如果当前正在调整中,又触发了 resize 事件,需要将上次调整暂停后执行这次调整(见 timedChunk 函数); b,resize 触发会很频繁,可以将回调函数缓存一段时候后执行,即当这段时间内多次触发了resize事件,但回调函数只会执行一次(见 S.buffer 函数)
  • 感兴趣的可以参见源码。

2) 异步加载数据,前面讲的是如何对容器中已有元素进行排列,但很多情况下,还需要不断加载新数据块,为此专门设计了一个独立的模块 KISSY.Waterfall.Loader,其实这个功能就更简单了,仅包含两个步骤:

  • 绑定滚动事件,并确定预加载线高度值,即滚动到哪个高度后,需要去加载数据,其实这个就是列的最小高度值,这样当前滚动值和最小高度值比较一下即可判断出来,是否要触发加载数据;
  • 加载数据,为了不对数据源做太多限制,完全由使用者自己决定数据源从哪边获取和其格式,这样更好的方便用户使用。为此,该组件只提供一个 load(success,end) 接口,怎样load 由用户自己去定义,而其中的 success/end,分别给出如何添加新数据(suceess 即同 addItems)/如何停止加载的接口。这样真是太方便了~~
  • 感兴趣的可以参见源码。

KISSY.Waterfall 示例和文档

看到这边,是不是很想试用一下~~ 嗯嗯,这里给出一些相关学习资料和示例,以供参考:

  • Waterfall API 文档,相关构造器,配置项,方法都在这里;
  • 示例,包含静态和动态两种。

欢迎试用和提出意见~~

二、稍稍要紧的话

跟风,尤其受pinterest的煽风点火,瀑布流现在不少人关注。我正好最近比较闲,加上有人曾在我站点提出希望我介绍点瀑布流的东西,所以,今儿个也随下大流。

pinterest以及上面迅雷UED xwei的瀑布流demo(至少在FireFox下还是有致命的显示bug的)都是采用的绝对定位实现的,有相对复杂的位置计算。

我一向不喜欢吃别人嚼过的米饭,于是尝试使用另外的原理实现。我是个流体布局控,对绝对定位啊、浮动啊什么的一向没什么好感,于是,这里要介绍的就是基于多栏列表流体布局实现的瀑布流布局效果。

大致结构、布局见下面的手绘图:
流体布局下的瀑布流结构草图 张鑫旭-鑫空间-鑫生活

没有复杂的位置计算,不需要知道里面元素的高度以及宽度,且易理解,关键是具体实现~~

三、高潮来了:demo展示

您可以狠狠地点击这里:基于多栏列表瀑布流布局demo

瀑布流demo页面效果截图 张鑫旭-鑫空间-鑫生活

欢迎各种滚动,缩放等测试。低版本IE浏览器也是兼容滴。问题嘛也是有滴,就是滚动到一定位置再F5刷新的时候,部分加载的内容有丢失,需要重新滚 动加载。这个嘛,我个人觉得小小demo,没必要折腾啦(实际上要实现也比较容易,改动如下:每次滚动不是append一个节点,而是连续回调直到加载到 屏幕下方。不懂什么意思?花点功夫看看JS实现原理就会明白了)~~

四、说说原理

第一次进入的时候,根据浏览器宽度以及每列宽度计算出列表个数,然后不管三七二十一,每列先加载个5张图片再说。

当滚动的时候,对每一列的底部位置做检测,如果在屏幕中或屏幕上方,则立即append一个新图片(注意:为了简化代码,提高性能,同时便于演示等,这里只append了一个)。因为,滚动时连续的,因此,我们实际看到的效果是图片不断load出来。

当浏览器宽度改变的时候,页面上有个idwaterFallDetectspan标签,这个标签作用有两个:一是实现两端对齐效果,二是用来检测瀑布流布局是否需要刷新。

检测原理如下:
span标签宽度与一个列表宽度一致,当浏览器宽度变小的时候,如果小到一定程度,显然,浏览器最右边的列表就会跑到下一行,把空span挤到后面去,空span发生较大的水平位移,显然,可以通知脚本,布局需要刷新;当浏览器宽度变大的时候,如果变大的尺寸超过一列的宽度,显然,这个空span灰跑到第一行去,同样是发生较大的水平位移,因此,又可以通知脚本刷新瀑布流布局了。

这个方法的好处是几乎没有计算就可以一点不差地知道何时瀑布流布局需要刷新。这显然要比设置resize定时器+位置尺寸计算要简单高性能地多。

浏览器宽度变小时触发瀑布流更新的原理示意 浏览器宽度变宽时触发的瀑布流更新原理示意

滚动时的页面刷新是基于HTML字符串的处理,而不是更改每个DOM元素的位置(这是绝对定位实现的处理),因此,这里的效率显然更高。

五、总结:基于多栏列表流体布局瀑布流效果优点

  1. 简单:最大限度利用了浏览器的流体特性进行布局,省去了很多计算的麻烦;新人更易懂和上手
  2. 更好的性能:这个体现在多处,如浏览器宽度改变,瀑布流刷新时候的效率等
  3. 无需知晓尺寸:如果是要绝对定位实现瀑布流,必须知道每个小模块的高度以及宽度(否则无法定位),而基于列表的布局则无需知道高宽

无聊时候的折腾,有不足与不准确之处欢迎指正。一些实现的具体细节等也是非常欢迎提问交流的。

原创文章,转载请注明来自 张鑫旭-鑫空间-鑫生活[ http://www.zhangxinxu.com]

你可能感兴趣的:(瀑布流布局(基于多栏列表流体布局实现))