瀑布流布局的原理
一个页面设定好等宽的元素纵向布局,根据每个元素的高度不同,找出最小高度, 将第二排以后的元素挨个放在下面,实现的效果入下:
废话不多说, 开始上代码,代码里面每行都有详细的注释
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
*{
margin: 0;
padding: 0;
}
html, body{
overflow: hidden;height: 100%;
}
.pubuliu{
position: relative;
}
.pubuliu p{
position: absolute;
display: inline-block;
width: 100px;
margin: 5px;
background: #ccc;
transition: all .3s;
}
</style>
</head>
<body>
<div class="pubuliu">
<p style="width: 100px; height: 100px"></p>
<p style="width: 100px; height: 70px"></p>
<p style="width: 100px; height: 150px"></p>
<p style="width: 100px; height: 250px"></p>
<p style="width: 100px; height: 80px"></p>
<p style="width: 100px; height: 90px"></p>
<p style="width: 100px; height: 120px"></p>
<p style="width: 100px; height: 210px"></p>
<p style="width: 100px; height: 230px"></p>
<p style="width: 100px; height: 100px"></p>
<p style="width: 100px; height: 70px"></p>
<p style="width: 100px; height: 150px"></p>
<p style="width: 100px; height: 250px"></p>
<p style="width: 100px; height: 80px"></p>
<p style="width: 100px; height: 90px"></p>
<p style="width: 100px; height: 120px"></p>
<p style="width: 100px; height: 210px"></p>
<p style="width: 100px; height: 250px"></p>
<p style="width: 100px; height: 80px"></p>
</div>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
<script>
//列数
var colCount = 0;
//定义列高度数组
var colHeightArry = [];
//每个 p 的宽度
var pWidth = $('.pubuliu p').outerWidth(true);
// 页面上来初始化 p 元素
function init() {
//用整个元素的宽度 除以 p的宽度得出列数
colCount = parseInt($('.pubuliu').width() / pWidth);
// 便利列数,给列高数组赋值 colHeightArry=[0, 0, 0, 0]
for(var i = 0 ; i < colCount; i ++){
colHeightArry[i] = 0
}
// p元素一个一个的加载到页面上
$('.pubuliu p').on('load',function() {
//定义最小的高度, 取列高数组的第一个值
var minValue = colHeightArry[0];
//定义最小高度的下标 0
var minIndex = 0;
// 便利列数, 判断列高小于上面定义的最小高度,将当前的列高赋值给最小值,并且重新赋值当前最小值的索引
for(var i = 0 ; i < colCount; i ++) {
if(colHeightArry[i] < minValue){
minValue = colHeightArry[i];
minIndex = i;
}
}
// 开始赋值当前的p元素left和top值
$(this).css({
left: minIndex * pWidth,
top: minValue
})
// 将当前的p元素的高度给列高
colHeightArry[minIndex] += $(this).outerHeight(true)
})
}
init();
//当窗口大小重置之后,重新执行
$(window).on('resize',function(){
reset()
})
//当窗口加载完毕,执行瀑布流
$(window).on('load',function(){
reset()
})
//定义reset函数
function reset(){
var colHeightArry= []
// 计算多少列
colCount = parseInt($('.pubuliu').width() / pWidth)
// 赋值列高 colHeightArry
for(var i = 0 ; i < colCount; i ++){
colHeightArry[i] = 0
}
// 取到p元素集合便利
$('.pubuliu p').each(function() {
var minValue = colHeightArry[0]
var minIndex = 0
for(var i = 0 ; i < colCount; i ++){
if(colHeightArry[i] < minValue){
minValue = colHeightArry[i]
minIndex = i
}
}
$(this).css({
left: minIndex * pWidth,
top: minValue
})
colHeightArry[minIndex] += $(this).outerHeight(true)
})
}
</script>
</body>
</html>
原生js(实现瀑布流)
const propsValue = reactive({
list: [
{ height: 200, background: 'red' },
{ height: 300, background:'red' },
{ height: 500, background:'yellow' },
{ height: 200, background:'blue' },
{ height: 800, background:'green' },
{ height: 100, background:'yellow' },
{ height: 500, background:'green' },
{ height: 600, background:'red' },
{ height: 700, background:'red' },
{ height: 900, background:'yellow' },
{ height: 200, background:'red' },
{ height: 300, background:'gray' },
{ height: 700, background:'gray' },
{ height: 300, background:'red' },
{ height: 500, background:'yellow' },
{ height: 200, background:'blue' },
{ height: 800, background:'green' },
{ height: 100, background:'yellow' },
{ height: 500, background:'green' },
{ height: 600, background:'red' },
{ height: 700, background:'red' },
{ height: 900, background:'yellow' }
]
})
let waterList = reactive<any[]>([]) // 整个元素对象 包含width、height、left、top、background
let heightList: number[] = [] // 维护一个高度数组
onMounted(() => {
const width = 130 // 每个元素的宽度
const x = document.body.clientWidth // 可视区域的宽度
const column = Math.floor(x / width) // 每一行摆放几个元素
for (let i = 0; i < propsValue.list.length; i++) { // 便利所有的元素
if(i < column) { // 只找第一行的元素
// 给第一行的元素设置left和top值
propsValue.list[i].left = i * width
propsValue.list[i].top = 20
waterList.push(propsValue.list[i])
heightList.push(propsValue.list[i].height)
}else{ // 第二行开始找
let current = heightList[0] // 默认第一个元素是最小的
let index = 0 // 默认第一个元素是最小的,记录一下索引的位置,方便给元素设置left的值
heightList.forEach((item, i) => { // 找第一行已经放好的元素的高度最小的那个元素
if(current > item) { // 找到后面的元素,要是比前面的元素的高度小的话就换当前元素和索引
current = item
index = i
}
})
/** 此时 current 是已经排放好的最小元素的高度, index 是已经摆放好的最小元素的索引 **/
// 找到已经排放好的高度最小的那个元素,赋值给下一个即将要放上去的元素的 left 和 top
propsValue.list[i].top = current + 40
propsValue.list[i].left = index * width
// 找到最小高度元素的位置(已经排放好的) 加上 即将要放上去的元素的高度 重新赋值给当前最小高度 元素的高度
heightList[index] = heightList[index] + propsValue.list[i].height + 20
// 最终放到waterList往页面上渲染
waterList.push(propsValue.list[i])
}
}
})
弹性和布局折行补元素
效果入下
实现思想
在mounted里面计算需要补充多少个元素li
const wrap = document.body.clientWidth // 可视区的宽度
const li = document.querySelectorAll(".cart-li") // 每个li的宽度
const columnNum = Math.floor(wrap.offsetWidth / li[0].offsetWidth) // 一行放多少个元素
const num = columnNum - (this.cartList.length % columnNum) // 渲染的元素个数 余上 一行几个元素,再用一行几个元素 减去 就得出需要补充多少个元素
for(let i = 0; i < num; i++) {
this.cartList.push({}) // 补充元素(注意: 补充的元素没有id)
}
data里面的数据
data() {
return{
// 原始元素有id
cartList: [
{id: 1},
{id: 2},
{id: 3},
{id: 4},
{id: 5},
{id: 6},
]
}
}
样式就用弹性盒布局就行
父元素
.cart{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
补充的元素不让他们展示出来,只是占位
.cart-li-none{
opacity: 0;
}
<div class="cart">
<li :class="item.id ? 'cart-li' : 'cart-li cart-li-none'" v-for="(item, index) in cartList" :key="index"> <!-- 通过有没有id来加class,实现补充的元素不展示,只是占位 -->
<template v-if="item.id"> <!--里面的内容要是没有id的话也不展示出来-->
<div class="title">li元素里面的内容</div>
</template>
</li>
</div>