Waterfall flow layout of the front-end div block

foreword

As shown in the figure, each category is a block. The number of categories is dynamic, and the number of items in each category is dynamic. The product manager requires a waterfall layout like the one in the figure. Learn from the waterfall flow layout of other people's pictures to realize the waterfall flow layout of this div block.
insert image description here

start

For the waterfall layout of pictures, there is a fixed width or a fixed height. I choose the fixed width method. But in reality, browsers have multiple screen widths, and it is necessary to set the width of each div block and be adaptive.
So here,
1. I use css to calculate and set the width of div blocks under different screens: For example, if the width is >1500, 5 columns can be placed, and the width of each column is removed, that is, 2. Set width:calc(100% - 30px*4)/5;each width:calc(20% - 24px);
div Blocks are absolutely positioned.
3. Use js to calculate the positioning position of each div block: the div blocks in the first row are arranged in sequence; starting from the second row, find the column with the smallest height each time, fill it, and then recalculate the column with the smallest height, and fill it in turn.
4. Due to the absolute positioning of the div block, the height of its parent element collapses. Use js to take the last highest column and set the height of the parent element.

upper code

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)
			
		}
	}

Finish

Record the problem here, if there is any need to modify, please let me know. Article reference: 5 ways to realize the layout of the waterfall flow with you

Guess you like

Origin blog.csdn.net/qq_39352780/article/details/118155077