总结实现瀑布流的三种方式

最近在参加一个小程序 比赛, 其中在开发页面的时候,设计图设计是瀑布流的样式。本以为很简单的浮动就能实现的。但是其实并没有那么简单。通过这次写瀑布流。感觉受益颇多。于是通过这篇博客记录一下瀑布流是如何实现的以及每个方法的原理。

什么是瀑布流?

瀑布流我们又称瀑布流式布局。这种布局视觉表现为参差不齐的多栏布局,随着页面的滚动条向下滚动,还会不断加载数据块并附加到当前结尾。瀑布流布局即不会出现错乱现象,而且会最大限度显示图片的内容。

瀑布流的原理

瀑布流的原理就是页面容器内多个高度不固定的div之间按照一定的间隔参差不齐的无序浮动,数据滚动时不断的在容器内的尾部加载数据,且自动加载到空缺位置。不断循环。瀑布流布局的核心就是基于一个网格的布局,而且每行包含的项目列表的高度(高度)是随机的(随着自己的内容动态变化的高度或者宽度)。

等宽瀑布流

根据以上的瀑布流的原理我们也知道,瀑布流可以分为两种形式:等宽瀑布流,等高瀑布流。。我们这篇博文主要讲等宽瀑布流

等宽瀑布流形式如下:

我们可以看出来, 每块的宽度是一定的,但是高度是不一样的,其中高度取决于图片的高度。

我们来使用具体几种方式来实现:

css 实现:column-count 方式

column-count: 用于定义栏目的的列数

1
column-count:auto | 整数
  • auto: 取计算机值
  • 整数:有浮点数和单位标识符组成的长度值,不可为负数

浏览器的兼容:

类型 IEInternet Explorer FirefoxFirefox ChromeChrome OperaOpera SafariSafari
版本 (×) IE6 (×) Firefox 2.0 (√ )Chrome 1.0.x (× )Opera 9.63 (√)Safari 3.1
(×)IE7 (×) Firefox 3.0 (√) Chrome 2.0.x (√)Safari 4
(x)IE8 (√ )Firefox 3.5

可以看出还是有很多浏览器不兼容的。使用的时候还是很需要谨慎。

所有有些浏览器前缀是必要的:

引擎类型 Gecko Webkit Presto
column-count -moz-column-count -webkit-column-count

具体的瀑布流的例子:

其中例子重要的代码其实也就是如下的代码:

1
2
3
4
5
column-count: 2;
column-gap: 10px;
-webkit-column-count: 2;
-webkit-column-gap: 10px;
-webkit-column-gap: 10px;

其中 column-gap 属性用来设置元素列之间的间隔大小。

但是这种方式有一个缺点:数据不是从上到下排列, 而是从左到右边的排列方式。在例子中可以看出来,1,2,3,4 是在左边的一列的。左边的排完了,才到右边的。

而且这次的360家小程序 。 我们在模拟器上和一些手机上这种方式实现是ok的。但是8p, 5s在我们360家app 上是不支持的。 使用还是需要谨慎。

css实现: display: flex 方式

如果还不了解弹性布局的可以先看 Flex布局教程

实现原理:

  1. 先使用: display: flex;, flex-direction: row;将容器的主轴变成垂直方向。
  2. 然后再使用: justify-content: space-between;将主轴的列两端对齐。
  3. 我们需要几列就需要把数据分为几列。

具体例子:

例子的主要代码:

1
2
3
display: flex;
flex-direction: row;
justify-content: space-between;

这主要是布局的代码

1
2
3
4
5
6
7
8
9
10
11
// 加载数据, 把数据分成两列
onLoadImg() {
for (let i = 0; i < 18; i++) {
let colIndex = i % 2 ; // 两列
let url = `https://shuliqi.github.io/xiaozhan/${i + 1}.jpeg`;
if (this.imgList[colIndex]) {
this.imgList[colIndex].push(url)
} else {
this.$set(this.imgList, colIndex, [url])
}
}

这主要将数据变成多少列的代码

缺点:

当然了这也是有缺点的。就是可能某一列特别长。以为我们在将数据分为几列的时候, 并没有判断图片的高度,而放入不同的列当中。

JS 计算方式

js实现的具体步骤:

  1. 确定每行放几张图片, 每行的个数(column)=页面宽度(pageWidth)/(图片盒子宽度+图片间距)
  2. 确定一行多少个之后首先需要将第一行排列好 (绝对定位的方式,使用js排列好)
  3. 找出每一行的最小高度,排列完每一张图片之后更新最小高度

具体的实现:

其中重要的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
waterFall() {
var items = document.getElementsByClassName('img-item');
if (items.length === 0) return;
//定义间隙10像素
var gap = 20;
//首先确定列数 = 页面的宽度 / 图片的宽度
var pageWidth = this.$refs.waterfall.offsetWidth;

var itemWidth = items[0].offsetWidth;
var columns = parseInt(pageWidth / (itemWidth + gap));

var arr = [];//定义一个数组,用来存储元素的高度
for(var i = 0;i < items.length; i++){
if(i < columns) {
//满足这个条件则说明在第一行,文章里面有提到
items[i].style.top = 0;
items[i].style.left = (itemWidth + gap) * i + 'px';
arr.push(items[i].offsetHeight);
}else {
//其他行,先找出最小高度列,和索引
//假设最小高度是第一个元素
var minHeight = arr[0];
var index = 0;
for(var j = 0; j < arr.length; j++){//找出最小高度
if(minHeight > arr[j]){
minHeight = arr[j];
index = j;
}
}
//设置下一行的第一个盒子的位置
//top值就是最小列的高度+gap
items[i].style.top = arr[index] + gap + 'px';
items[i].style.left = items[index].offsetLeft + 'px';

//修改最小列的高度
//最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 间隙的高度
arr[index] = arr[index] + items[i].offsetHeight + gap;
}
}
},

js 实现目前来说是最好的方式, 我们也是采用的这种方式。 但是在使用的过程中也有一些问题,就是在图片还没加载出来的是, 是获取不到每个容器img-item的offsetHeight。 所以有时候会有重叠的时候。

目前总结的就这三种方式,可以按需使用。

文章作者: 舒小琦
文章链接: https://shuliqi.github.io/2020/11/17/瀑布流的实现方式/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 舒小琦的Blog