前言
如图,每个类别是一个块。类别个数是动态的,每个类别的条数是动态的,产品经理要求做成图中这样的瀑布流布局。借鉴别人图片的瀑布流布局,来实现这个div块的瀑布流布局。
开始
对于图片的瀑布流布局来说,有定宽或者定高。我选择定宽的方法。但是在实际情况中,浏览器有多种屏幕宽度,既要给每个div块定宽,又要做到自适应。
所以在这里,
1、我用css计算并设置不同屏幕下div块的宽度:如在>1500宽度下,可以放置5列,除去中间的间距,每列宽度为width:calc(100% - 30px*4)/5;
,也就是width:calc(20% - 24px);
2、设置每个div块绝对定位。
3、用js算每个div块的定位位置:第一行div块依次排开;第二行起,每次找高度最小的那一列,填补,再重新计算高度最小的一列,依次填补。
4、由于div块绝对定位,其父元素高度坍塌,用js取最后最高的一列,设置父元素高度。
上代码
html
<ul :style="{height:ulHeight+'px'}" ref="content">
<li v-for="(item,index) in blockList"
:style="{left:item.left+'px',top:item.top+'px',height:item.height+'px'}"
v-if="item.serviceData.length>0">
<p>{{item.typeName}}</p>
<div class="knowledgeContent">
<div class="knowledgeItem"
v-for="item1 in item.serviceData"
@click="checkDetail(item,item1)">
<i class="itemPoint"></i>
<span>{{item1.title}}</span>
</div>
</div>
</li>
</ul>
css
ul{
position: relative;
li{
width: calc(20% - 24px);
border: 1px solid #DBDBFD;
box-shadow: 0 2px 4px 2px #EBEBEB;
padding-bottom: 10px;
position: absolute;
p{
height: 50px;
line-height: 50px;
padding: 0 15px;
background: url(../../../assets/img/csManager/knowledgeItemBg.png) ;
font-family: PingFangSC-Medium;
font-size: 14px;
color: #000000;
}
.knowledgeContent{
.knowledgeItem{
padding: 10px;
cursor: pointer;
i{
display: inline-block;
width: 6px;height: 6px;
border-radius: 50%;
background: #A7A6DA;
margin-right: 8px;
vertical-align: top;
margin-top: 7px;
margin-right: 10px;
}
span{
display: inline-block;
vertical-align: top;
width: calc(100% - 25px);
font-size: 14px;
color: #000;
}
&:hover{
i{
background: #302e77;
}
span{
color: #302E77;
}
}
}
}
}
}
@media screen and(max-width:1500px){
ul {
li{
width: calc(25% - 22.5px);
}
}
}
javascript
export default {
data () {
return {
colNumbers:0,//列数
colWidth:0,//块宽度
colHeight:[],//块高度数据列表,用来查找最小高度,从而实现瀑布流算法
ulHeight:0,//ul高度(因子元素绝对定位,父元素高度塌陷,故取colHeight最大值加内边距10)
list:[
{typeName:'类别1',
seviceData:[{id:1,title:'标题1'}]
}
],
blockList:[],//含有定位位置的列表,用来循环显示
}
},
methods:{
//计算块列数,>1500时为5列,<=1500 时,为4列,间距为30
getColNumbers() {
let screenwidth = document.documentElement.clientWidth;
if(screenwidth>1500){
this.colNumbers = 5;
this.colWidth = (this.$refs.content.clientWidth - 30*4)/5;
}else{
this.colNumbers = 4;
this.colWidth = (this.$refs.content.clientWidth - 30*3)/4;
}
},
//读取块,设置高度信息
loadBlock() {
this.getColNumbers();
for(let i =0; i < this.list.length; i++){
//1.求本块高度
let height = 80;
this.list[i].serviceData.forEach(item=>{
if(item.title.length>15){//标题超过15字,换行,此条高度为62px(标题限制为20字)
height+=62;
}else{
height+=41;
}
})
//2.传参调用方法
this.render({
index:i,
height:height,
...this.list[i]
})
}
//3.因子元素全部绝对定位,父元素高度用js计算得到,取高度最大值
this.ulHeight = Math.max.apply(null, this.colHeight);
},
//设置渲染块的list
render(blockInfo){
let colIndex = blockInfo.index % this.colNumbers;
if (blockInfo.index < this.colNumbers) {//首行:top为 0,记录每列的高度
blockInfo.top = 0
this.colHeight[colIndex] = blockInfo.height;
blockInfo.left = colIndex == 0? colIndex * this.colWidth :(colIndex * this.colWidth+30*colIndex) ;
} else {
//获取高度的最小值
let minHeight = Math.min.apply(null, this.colHeight)
let minIndex = this.colHeight.indexOf(minHeight)
//此块的 top 为上面块的高度,left 相等
blockInfo.top = minHeight + 30;
let minColIndex = minIndex % this.colNumbers;//计算最小的在哪一列
blockInfo.left = minColIndex == 0? minColIndex * this.colWidth :(minColIndex * this.colWidth+30*minColIndex) ;
//把高度加上去
this.colHeight[minIndex] += 30+blockInfo.height;
}
this.blockList.push(blockInfo)
}
}
结束
在此记录问题,如有需要修改的地方,还请不吝赐教。文章借鉴:手把手带你撸瀑布流布局的5种实现方式