说到瀑布流的布局,相信大家都很熟悉。对于一些图片和数据流的瀑布加载,页面体验提升了很多。这里有一些实现的方法。
这种布局适用于小数据块,每个数据块内容相似,没有重点。通常,随着页面滚动条向下滚动,这种布局将继续加载数据块并附加到当前的尾部。因此,我们给这个布局起了一个形象的名字 —瀑布流式布局。
几种实现方法
随着越来越多的设计师喜欢使用这种布局,作为前端,我们应该尽可能满足视觉/交互设计师的需求。因此,我们整理了三种实现这种布局的方法:
1)传统的多列浮动。即 蘑菇街和哇哦 如下图所示:
-
每列固定宽度,左浮;
-
列中的数据块是一组,列中的每个数据块都可以依次排列;
-
在加载更多数据时,需要分别插入不同的列;
-
线上例子。
优点:
-
布局简单,应该说没有特别的困难;
-
不需要清楚地知道数据块的高度,当数据块中有图片时,不需要指定图片的高度。
缺点:
-
列数固定,不易扩展。当浏览器窗口大小发生变化时,只能固定x列。如果要添加一列,则很难调整数据块的排列;
-
滚动加载更多数据时,不方便指定插入第几列。
2) CSS3 定义。W3C 有一个关于它的故事多列文档布局,排列的样子:
-
由 chrome/ff 浏览器直接渲染,可指定容器的列数、列间距、列中间边框、列宽度;
#container { -webkit-column-count: 5; /*-webkit-column-gap: 10px; -webkit-column-rule: 5px solid #333; -webkit-column-width: 210px;*/ -moz-column-count: 5; /*-moz-column-gap: 20px; -moz-column-rule: 5px solid #333; -moz-column-width: 210px;*/ column-count: 5; /*column-gap: 10px; column-rule: 5px solid #333; column-width: 210px;*/ }
-
column-count 为列数; column-gap 每列间隔距离; column-rule 间隔边线大小; column-width 为每列宽度; 当只设置 column-width 当浏览器窗口小于一列宽度时,列中的内容会自动隐藏; 当只设置 column-count 时,每列宽度的平均计算,如果列内容超过,则隐藏; 都设了 column-count 和column-width,根据浏览器 count 计算宽度和 width 将大值作为每列宽度进行比较,然后当窗户缩小时,width 每列的最小宽度是值。其实这里很简单。自己试试很容易。详情请参考 https://developer.mozilla.org/en/CSS3_Columns 中的说明。
-
线上例子。
优点:
-
直接 CSS 定义,最方便;
-
扩展方便,可以直接添加到容器中。
缺点:
-
只能在高级浏览器中使用;
-
另一个缺点是,他的数据块从上到下排列到一定高度,然后依次将剩余元素添加到下一列,这本质上是不同的;
-
鉴于这两个主要缺点,注定该方法仅限于高端浏览器,更适合文本多栏排列。
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)/如何停止加载界面。这样真的很方便~~
-
有兴趣的可以参见源码。