背景
在工作中我们或多或少都遇到过需要用到瀑布流的列表或者需求,那么我们怎么实现瀑布流呢?今天我就给大家带来一个简单的实现方法。给大家做打个样。
技术
- vue3
- vite
源码地址
后面有时间会将此源码封装成公共组件库-->供大家下载使用--如果大家感兴趣的话可以关注一下
HTML
html
<template>
<div>
<button @click="addCard">增加</button>
<div class="card">
<div class="card-list"
v-waterfall
v-for="(item,index) in list" :key="index"
:style="{backgroundColor:item.color,height:item.height}"
>
<p class="text"> {{ index }} </p>
</div>
</div>
</div>
</template>
css
这儿注意-->因为在js中我使用的是transform,所以需要使用到定位
css
.card {
position: relative;
display: flex;
flex-wrap: wrap;
width: 700px;
}
.card-list {
position: absolute;
width: 200px;
}
js
实现逻辑:
- 声明一个列表的高度数组,保存每列的高度,然后获取最小高度的位置,方便定位过去
- 自定义指令:v-waterfall-->通过mounted拿取到dom元素
- 获取每列的最小高度就是你当前元素需要的top值,然后根据最小高度的索引值*宽度=left值
- 最后将其赋值给transform即可--
- 然后将高度在此(tabulationHeights)基础上叠加即可下次计算
基本逻辑也就完成了。简单吧
javascript
import { onMounted, ref, nextTick } from "vue";
const list = ref([
{color:'#76da6e',height:'100px'},
{color:'#40a988',height:'70px'},
{color:'#2384c4',height:'120px'},
{color:'#106ba3',height:'80px'},
{color:'#0a589e',height:'110px'},
{color:'#0a4e98',height:'90px'},
{color:'#09408c',height:'100px'},
{color:'#083680',height:'130px'},
]);
const tabulationHeights = ref([0,0,0,0]);
const updateLayout = (el) => {
const columns = getMinTabulationHeight(tabulationHeights.value);
const top = tabulationHeights.value[columns];
const left = columns * el.clientWidth;
el.style.transform = `translate(${left}px,${top}px)`;
tabulationHeights.value[columns] += el.offsetHeight;
}
const getMinTabulationHeight = (arr) =>{
let min = Math.min(...arr);
return arr.indexOf(min) !== -1 ? arr.indexOf(min) : 0;
}
const vWaterfall = {
mounted: (el) => {
updateLayout(el);
},
updated: (el) => {
// updateLayout(el);
}
}
// 增加
const addCard = () => {
// 随机生成高度
const height = Math.floor(Math.random() * 50 + 100);
// 随机生成颜色
const color = '#'+Math.floor(Math.random()*16777215).toString(16);
list.value.push({color,height:height+'px'});
}
疑问
有朋友可能会问:我列表与列表之间肯定不会没有间隔才对啊!那么请问这个有怎么处理呢?
其实这个很简单,比如你是要封装一个组件的话,你只需要传递一个GAP的值:然后拿到这个间距去参与计算即可:如以下代码
javascript
const updateLayout = (el) => {
const columns = getMinTabulationHeight(tabulationHeights.value);
const top = tabulationHeights.value[columns] + 20;
const left = (columns * el.clientWidth) + (columns * 20);
el.style.transform = `translate(${left}px,${top}px)`;
tabulationHeights.value[columns] += el.offsetHeight + 20;
}
总结
以上只是一个简单的模板,大家可以在此基础上优化优化以便达到自己需要的要求。今天的分享到这里就结束了哦!下次有好的点在来跟大家分享,如果觉得不错可以收藏哈这个源码库,后续会更新插件库