瀑布流
1.什么是瀑布流
- 特点
- 内容以垂直滚动的方式呈现,形成类似瀑布的视觉效果。
- 每个独立的内容块都是一个完整的视觉单元,可以独立浏览。
- 内容块之间没有明显的分隔边界,给人一种连贯流畅的视觉体验。
- 这种布局方式适用于展示大量内容,如新闻、博客文章、产品列表等。
- 瀑布流布局可以根据用户的滚动行为自动加载更多内容,提升用户体验。
- 该布局模式广泛应用于各类移动端和PC端网站,尤其适用于内容密集型网站。
2. 瀑布流的原理以及实现
2.1 父页面获取数据
部分关键代码如下
<script>
// 获取&&加工数据
const list = ref<any[]>([]);
onMounted(() => {
fetch("https://api.thecatapi.com/v1/images/search?limit=100&api_key=YOUR_API_KEY")
.then((res) => res.json())
.then((res) => {
const _res = res.map((item: any) => {
return {
...item,
height: Math.round(item.height / item.width * 120),
width: item.width,
}
})
list.value = _res
});
});
</script>
<template>
<waterFallView :waterList="list" />
</template>
2.2 子页面渲染视图
<script setup lang="ts">
import { reactive, watch } from "vue";
const props = defineProps<{
waterList: any[];
}>();
const _waterList = reactive<any[]>([]);
const heightList: number[] = [];
watch(
() => props.waterList,
() => {
init();
}
)
const init = () => {
const width = 130; // 每一项宽度设置大一点,每一列之间间距就可以大一点
const clientWidth = document.body.clientWidth; // 窗口可视区域宽度
const cols = Math.floor(clientWidth / width); // 列数
for (let i = 0; i < props.waterList.length; i++) {
// 第一行的
if (i < cols) {
props.waterList[i].left = i * width; // 左偏移
props.waterList[i].top = 0;
_waterList.push(props.waterList[i]);
heightList.push(props.waterList[i].height);
} else {
// 其他行的
// 1. 找到最短的那一列
let minHeight = heightList[0]; // 假设第一个最短
let minIndex = 0;
for (let j = 0; j < heightList.length; j++) {
if (minHeight > heightList[j]) {
minHeight = heightList[j]; // 最短列高度
minIndex = j;
}
}
// 2. 设置当前item的left和top
props.waterList[i].top = minHeight + 10; // 距离第一行的偏移量 = 最短列高度 + 间距
props.waterList[i].left = minIndex * width; // 左偏移
// 3. 更新高度数组
heightList[minIndex] += props.waterList[i].height + 10; // 最矮的高度 + 新加上去的高度 + 间距
// 3. 更新视图
_waterList.push(props.waterList[i]);
}
}
};
</script>
<template>
<div class="hy-waterfall__wrapper">
<div
v-for="item in _waterList"
class="hy-waterfall__item"
:style="{
height: item.height + 'px',
background: item.background,
left: item.left + 'px',
top: item.top + 'px',
}"
>
<img :src="item.url" alt="item.id" loading="lazy">
</div>
</div>
</template>
<style scoped lang="scss">
@include b(waterfall) {
@include e(wrapper) {
position: relative;
}
@include e(item) {
position: absolute;
width: 120px; // 定义每个item的宽度
img{
position: absolute;
width: 100%;
}
}
}
</style>
3. 效果图
4. 总结
先固定宽度,让图片自适应,算出每一张图片的高度。维护一个高度数组,用来存储每一列的高度。在每一行插入完成后,往最矮的那一列插入图片,并且更新高度数组,依次往复,直到所有的图片被插入到视图中。
感谢小满老师。