之前在插件里做了一个收藏夹和生词本的需求,大概长下面这样,里面的数据是按照瀑布流去做展示的

一、纯css也很好用
瀑布流布局一般的解决方案都是使用js去做动态计算内容高度,然后把内容分配给最短的'管道',实现调补的效果,但是纯js计算起来太费事了
在我逛了一圈百度后,发现css的gird布局
完全可以实现瀑布流效果,可以减少很多计算
二、强大的gird
因为之前也没怎么使用grid,都是现查的,详细的可以看看这篇文章
gird是二维的布局,支持同时设置两个方向的数据,包括内容占比、间距等等,这样就很好办事了。我们可以直接设置'管道'的数量,内容动态去设置格子占比即可
话不多说,先封装容器组件 <WaterFall />
1.模板和参数
模板上,我们只要弄好容器就好了,里面展示什么内容不需要关心,直接用slot
就好了
参数不需要支持太多,配置下面的就够了
- col:管道的数量
- colGap:管道的列间距
- girdRowHeight:每一个网格的高度
- rowGap:内容间行间距
vue
<template>
<div class="waterfall-wrapper" ref="waterfallRef" :style="wrapperStyle">
<slot></slot>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
col: {
type: Number,
default: 3
},
colGap: {
type: Number,
default: 20
},
girdRowHeight: {
type: Number,
default: 5
},
rowGap: {
type: Number,
default: 20
}
})
</script>
<style leng="scss" scoped>
.waterfall-list-wrapper {
display: grid;
align-items: start;
}
</style>
4.容器的配置style
vue
const wrapperStyle = computed(() => {
return {
// 需要多少列,每一列均分空间
'grid-template-columns': `repeat(${props.col}, 1fr)`,
// 隐式网格的高度
'grid-auto-rows': `${props.girdRowHeight}px`
}
})
4.动态计算内容占比
vue
const waterfallRef = ref(null)
const updateList = () => {
const els = Array.from(waterfallRef.value.children)
els.forEach((el: any) => {
// 内容占用的网格数
const contentRows = Math.ceil(el.clientHeight / props.girdRowHeight)
// 间距占用的网格数
const gapRows = Math.ceil(props.rowGap / props.girdRowHeight)
const rows = contentRows + gapRows
// 上边框自适应
el.style.girdRowStart = 'auto'
// 设置下边框为跨度 rows 个网格的大小
el.style.girdRowEnd = `span ${rows}`
})
}
执行updateList
,就可以实现瀑布流布局,如果有改变内容高度的操作,在操作完成后,再执行一遍updateList
即可
三、总结一下
使用gird布局去实现瀑布流的重点在于,预设好隐式网格的高度,计算出内容占用的网格数,再给gird的元素设置上
gird-row
即可