浅析瀑布流布局原理及实现方式

浅析瀑布流布局原理及实现方式

一、瀑布流

瀑布流布局有一个专业的英文名称Masonry Layouts。瀑布流布局已经有好多年的历史了,我最早知道这个名词的时候大约是在2012年,当时Pinterest网站的布局就是使用的这种流式布局,简言之像Pinterest网站这样的布局就称之为瀑布流布局,也有人称之为Pinterest 布局。

瀑布流又称瀑布流式布局,是比较流行的一种网站页面布局方式。即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。

瀑布流布局的核心是基于一个网格的布局,而且每行包含的项目列表高度是随机的(随着自己内容动态变化高度),同时每个项目列表呈堆栈形式排列,最为关键的是,堆栈之间彼此之间没有多余的间距差存大。还是上张图来看看我们说的瀑布流布局是什么样子。

1、为什么使用瀑布流

瀑布流布局在我们现在的前端页面中经常会用的到,它可以有效的降低页面的复杂度,节省很多的空间,对于整个页面不需要太多的操作,只需要下拉就可以浏览用户需要看到的数据;并且,在当前这个APP至上的时代,瀑布流可以提供很好的用户体验,通过结合下拉刷新,上拉加载进行数据的懒加载等操作,对于用户的体验感来说是接近于满分的!

2、瀑布流的特点

其实瀑布流的特点就是参差不齐的排列方式,以及流式布局的扩展性,可以通过界面展示给用户多条数据,并且让用户可以有向下浏览的冲动。

二、实现方式

1、纯 css 瀑布流:( multi-columns 方法 )

首先最早尝试使用纯CSS方法解决瀑布流布局的是CSS3 的Multi-columns。

其最早只是用来用来实现文本多列排列(类似报纸杂志样的文本排列)。但对于前端同学来说,他们都是非常具有创意和创新的,有人尝试通过Multi-columns相关的属性column-count、column-gap配合break-inside来实现瀑布流布局。

/* 这里是第一次接触到 column-columns 这个属性,这是一个可以设置将div元素中的文本分成几列 */

/* 默认值是:auto */

column-count:3;

-moz-column-count:3; /* Firefox */

-webkit-column-count:3; /* Safari and Chrome */

/* 注意:IE9及更早 IE 版本浏览器不支持 column-count 属性 */

/* 这里还会用到另一个属性 column-gap,用来调整边距,实现瀑布流布局 */

.demo-1{

-moz-column-count:3; /* Firefox */

-webkit-column-count:3; /* Safari 和 Chrome */

column-count:3;

-moz-column-gap: 1em;

-webkit-column-gap: 1em;

column-gap: 1em;

width: 80%;

margin:0 auto;

}

.item {

padding: 2em;

margin-bottom: 2em;

-webkit-column-break-inside: avoid;

break-inside: avoid; /*防止断点*/

background: #ccc;

text-align: center;

}

column-count和column-gap,前者用来设置列数,后者设置列间距。

上面控制了列与列之间的效果,但这并不是最关键之处。当初纯CSS实现瀑布流布局中最关键的是堆栈之间的间距,而并非列与列之间的控制(说句实话,列与列之间的控制float之类的就能很好的实现)。找到实现痛楚,那就好办了。或许你会问有什么CSS方法可以解决这个。在CSS中有一个break-inside属性,这个属性也是实现瀑布流布局最关键的属性。

其中break-inside:avoid为了控制文本块分解成单独的列,以免项目列表的内容跨列,破坏整体的布局。当然为了布局具有响应式效果,可以借助媒体查询属性,在不同的条件下使用column-count设置不同的列。

但是这里还是有个弊端,这并不符合瀑布流的原理,如果使用纯css写瀑布流,则每一块都是从上往下排列,不能做到从左到右排列,最主要的是不会识别哪一块图片放在哪个地方合适,若是再配合动态加载,效果会特别不好,所以只能通过JS来实现瀑布流。

2、瀑布流的位置分析图解

那么这里用图片来分析一下我们想要的瀑布流是什么样的。

如下方图片。假设一排放5张图片。当第一排排满足够多的等宽图片时,显示的是这样的。那么假如我们要放第6张图片的时候,应该放在什么位置呢?

如果按照我们的正常逻辑来想,应该是放在第一张图片下面,依次水平排列过去(如下图)

但现实并非如此!在瀑布流中,从第2行开始,接下去的每一张图片都会放在上行中高度最低的那一列图片下方。(如下图)

为什么呢?因为放置它之前,这一列的高度为所有列中最小,所以会放置在这个地方。

那么如果再继续放置下去,第七张图片应该放在第三列图片下方,以此类推。

所以每次加载图片时,会需要判断哪一列的图片累计的高度最小,那么下一张图片就放在哪一列,即瀑布流算法去判断图片的确定位置。

3、JS实现

结构示意图:

可扩展要素:(1)外层容器的box高度不固定;(2)每列col的宽度可自定义;(3)列数可自定义,取决于有几个数据dataList,每个列的数据对应一个 dataList。

(1)页面布局结构代码

{{item.text}}

{{item.text}}

{{item.text}}

{{item.text}}

(2)加载数据

当组件mounted时获取数据,获取到数据后执行mountMenu()方法,mountMenu()方法将会通过selectCol()选择当前高度最小的列,并把数据push到对应的dataList中,mountMenu()会在每次执行时递归调用,直到遍历完所有的数据。

export default {

data() {

return {

mainMenuList: [],

dataList1: [],

dataList2: [],

dataList3: [],

dataList4: [],

}

},

mounted() {this.mountMenu()

},

methods: {

mountMenu(arg) {

var temp = this.mainMenuList

var index = arg || 0

var refName = this.selectCol()

if (temp.length > index) {

this[refName].push(this.mainMenuList[index])

this.$nextTick(() => {

this.mountMenu(index + 1)

})

}

},

selectCol() {

var getHeight = (ref) => {

return this.$refs[ref].offsetHeight

}

var height1 = getHeight('col1')

var height2 = getHeight('col2')

var height3 = getHeight('col3')

var height4 = getHeight('col4')

switch (Math.min(height1, height2, height3, height4)) {

case height1:

return 'dataList1'

break

case height2:

return 'dataList2'

break

case height3:

return 'dataList3'

case height4:

return 'dataList4'

break

}

},

}

}

这样就可以实现一个我们想要的瀑布流了,但是不好的是频繁的取高度,会导致频繁的回流。所以如果不是一定要使用的话,就尽量避免吧。

相关推荐

什么鱼线最好用?不能一概而论,主要取决于钓法、鱼情等!
潘玮柏参加的综艺节目
365国际网站

潘玮柏参加的综艺节目

08-11 👁️ 188
分类:各媒体分类
谁有365比分链接

分类:各媒体分类

08-07 👁️ 7711
借呗10万一个月利息多少?全面解析利率与还款