瀑布流练习题
0. 瀑布流的形成
各种高度不同的方块平铺。需要注意的是,第二行开始,选高度最小的方块位置插入新的方块,即需要记住当前高度数组。
1. 父组件 瀑布流的容器
这里的number
是为了验证是否如开头所言,插入选取位置最矮的
<template>
<WaterFall :list="list"></WaterFall>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import WaterFall from '@/components/WaterFallCom/WaterFall/index.vue'
const list = [
{ height: 300, background: 'red' },
{ height: 400, background: 'pink' },
{ height: 100, background: 'black' },
{ height: 200, background: 'purple' },
{ height: 700, background: 'yellow' },
{ height: 800, background: 'blue' },
{ height: 900, background: 'grey' },
// 第二轮
{ height: 110, background: 'grey' },
{ height: 420, background: 'black' },
{ height: 210, background: 'pink' },
{ height: 290, background: 'blue' },
{ height: 510, background: 'yellow' },
{ height: 300, background: 'green' },
{ height: 100, background: 'red' },
// 第三轮
{ height: 800, background: 'red' },
{ height: 100, background: 'pink' },
{ height: 50, background: 'black' },
{ height: 120, background: 'purple' },
{ height: 300, background: 'yellow' },
{ height: 400, background: 'blue' },
{ height: 510, background: 'grey' },
// 第四轮
{ height: 300, background: 'red' },
{ height: 400, background: 'pink' },
{ height: 100, background: 'black' },
{ height: 200, background: 'purple' },
{ height: 700, background: 'yellow' },
{ height: 800, background: 'blue' },
{ height: 900, background: 'grey' }
].map((item, i) => ({ ...item, number: i }))
</script>
<style scoped lang="scss"></style>
2. 子组件 绘制瀑布流方块
<template>
<div class="wraps">
<div
class="items"
:style="{
height: item.height + 'px',
width: item.width + 'px',
top: item.top + 'px',
left: item.left + 'px',
background: item.background
}"
v-for="item in waterFallList"
>
{{ item.number }}
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
// 从父组件中获得值
const props = defineProps<{ list: any[] }>()
const originList = props.list
const waterFallList = reactive([])
const onInit = () => {
const heightList: any[] = []
const width = 130
// 获得可视宽度
const x = document.body.clientWidth
// 一行能容纳的个数
const column = Math.floor(x / width)
const originTop = 10
for (let i = 0; i < originList.length; i++) {
// 第一排
const isFirstFloor = i < column
if (isFirstFloor) {
originList[i].top = originTop
originList[i].left = i * width
// 顶部高度
heightList.push(originList[i].height + originTop)
// 放入瀑布流数组中
waterFallList.push(originList[i])
} else {
// 往后的需要注意维护高度数组,找最小的高度插入
// 找出当前最小的高度,插入新的方块
let current = heightList[0] // 比大小第一个
let minIndex = 0 // 默认序号是0
heightList.forEach((h, j) => {
// 将最小的保存
if (h < current) {
current = h
minIndex = j
}
})
// 当前找出的最小高度 + 顶格间距
originList[i].top = current + originTop
// 这里的左侧间距,是放置在最矮方块的下一行
originList[i].left = minIndex * width
// 同列上一个最小高度方块的高度 + 这一个方块的高度 + 两者之间间隔
heightList[minIndex] = heightList[minIndex] + originList[i].height + 20
// 将定位完成的方块 放入瀑布流中
waterFallList.push(originList[i])
}
}
}
onMounted(() => {
window.onresize = () => onInit()
onInit()
})
</script>
<style scoped lang="scss">
// 子绝父相能够使子节点按照父节点的标准进行绝对定位.
// 父级需要占有位置,因此是相对定位,子盒子不需要占有位置,则是绝对定位
.wraps {
position: relative;
.items {
position: absolute;
width: 120px;
}
}
</style>