瀑布流又称瀑布流式布局,以视觉表现为参差不齐的多栏布局为主,随着页面的滚动条不断向下滚动,这种布局会不断加载数据块并附加至当前尾部。实现这种布局有很多不同的方法:如flex布局,column-count 多栏布局,grid布局,float浮动布局。
flex实现瀑布流
先创建一个包住整个瀑布流的盒子,如果是2列,给该盒子设置display:flex;flex-wrap:wrap;完成这一步我们就可以有一个flex布局,超出该盒子宽度自动换行,然后在这个大盒子内部设置2个div容器,一列取奇数,一列取偶数即可简单进行实现
<view class="box">
<view v-for="(item,idx) in dataList" :key="idx">
<view v-if="idx%2==1"> {{item.img}} </view>
</view>
<view v-for="(item,idx) in dataList" :key="idx">
<view v-if="idx%2!=1"> {{item.img}} </view>
</view>
</view>
column-count 多栏布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>column多行布局实现</title>
<style>
.box {
margin: 10px;
column-count: 3; /* 是控制屏幕分为多少列 */
column-gap: 10px; /* 控制列与列之间的距离 */
}
.item {
margin-bottom: 10px;
}
img {
width: 100%;
}
</style>
</head>
<body>
<div class="box">
<div class="item">
<img src="https://img2.baidu.com/it/u=1337068678,3064275007&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=750" alt="">
</div>
<div class="item">
<img src="https://img2.baidu.com/it/u=2814429148,2262424695&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img2.baidu.com/it/u=3139110441,2189129638&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img2.baidu.com/it/u=3444890671,796356424&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img1.baidu.com/it/u=1286854971,3553024375&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/O6SG7dHjdG0kWNyWz6WPo2_3v6A6eAC9ThTazwlKPO1qMAA/641" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/O0e2a37GGF5CDfNgK8GU29rF_2eJlHLDsa17LABXns7V4AA/641" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/Os3eJ8u3SgB3Kd-zrRRhgfR5hUvdwcVPKUTNO6O7sZfUwAA/641" alt="">
</div>
<div class="item">
<img src="https://img0.baidu.com/it/u=1799694557,1475747482&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=750" alt="">
</div>
<div class="item">
<img src="https://pic.rmb.bdstatic.com/bjh/news/57e572cd41520408ebbbe5e3a6fb5b6d.jpeg" alt="">
</div>
</div>
<script>
</script>
</body>
</html>
grid布局
先通过grid布局设置列数以及列的宽度,并通过js代码设置元素上边距和元素所需占行数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>column多行布局实现瀑布流</title>
<style>
body {
margin: 0;
}
.box {
display: grid;
grid-template-columns: repeat(1, 1fr); /* 声明列的宽度 fr实现等分响应式*/
grid-gap: 0 20px; /* 声明行间距和列间距 */
grid-auto-rows: 2px; /* */
align-items: end;
}
.item {
display: flex;
justify-content: center;
align-items: center;
}
img {
width: 100%;
height: 100%;
}
/* 媒体查询 */
@media (min-width: 1280px) and (max-width: 1920px) {
.box {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 768px) and (max-width: 1280px) {
.box {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.box {
grid-template-columns: repeat(1,1fr);
}
}
</style>
</head>
<body>
<div class="box">
<div class="item">
<img src="https://img2.baidu.com/it/u=1337068678,3064275007&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=750" alt="">
</div>
<div class="item">
<img src="https://img2.baidu.com/it/u=2814429148,2262424695&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img2.baidu.com/it/u=3139110441,2189129638&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img2.baidu.com/it/u=3444890671,796356424&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="http://img1.baidu.com/it/u=1286854971,3553024375&fm=253&app=138&f=JPEG?w=800&h=1422" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/O6SG7dHjdG0kWNyWz6WPo2_3v6A6eAC9ThTazwlKPO1qMAA/641" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/O0e2a37GGF5CDfNgK8GU29rF_2eJlHLDsa17LABXns7V4AA/641" alt="">
</div>
<div class="item">
<img src="https://inews.gtimg.com/om_bt/Os3eJ8u3SgB3Kd-zrRRhgfR5hUvdwcVPKUTNO6O7sZfUwAA/641" alt="">
</div>
<div class="item">
<img src="https://img0.baidu.com/it/u=1799694557,1475747482&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=750" alt="">
</div>
<div class="item">
<img src="https://pic.rmb.bdstatic.com/bjh/news/57e572cd41520408ebbbe5e3a6fb5b6d.jpeg" alt="">
</div>
</div>
<script>
// 给每个元素模拟随机高度
window.addEventListener('load', () => {
document.querySelectorAll('.box > .item').forEach(item => {
item.style.height = `${Math.floor(Math.random() * 200) + 100}px`
})
})
const calcRows = () => {
const box = document.querySelector('.box')
const items = document.querySelectorAll('.item')
// 获取当前列数
const cols = getComputedStyle(box).gridTemplateColumns.split(" ").length
items.forEach((item, index) => {
// 给需要上下间隔的元素增加上间隔(每列第一个元素无需上间距)
const gapRows = index >= cols ? 8 : 0;
// 根据元素高度设置元素的需占行数
const rows = Math.ceil(item.clientHeight / 2) + gapRows;
// grid-row-end 属性:下边框所在的水平网格线
item.style.gridRowEnd = `span ${rows}`;
})
}
window.addEventListener('resize', calcRows)
window.addEventListener('load', calcRows)
</script>
</body>
</html>
float布局
uni-app实现移动端瀑布流布局时需要先设置几列,在进行循环创建几个div,在进行浮动,然后在每个div里面放置图片,使用js代码计算每个图片高度
<template>
<view class="container">
<Header title="瀑布流" alignAway="center" class="sticky-pos"/>
<!-- 浮动实现 -->
<view class="waterfalls-flow">
<view v-for="(item,index) in data.column" :key="index" class="waterfalls-flow-column"
:style="{'width':w,'margin-left':index==0?0:m}" :id="`waterfalls_flow_column_${index+1}`">
<view class="column-value" v-for="(item2,index2) in data[`column_${index+1}`]" :key="index2">
<image :src="item2.image" mode="widthFix" @load="imgLoad(item2)" @error="imgError(item2)" class="imgsty">
</image>
<text>{{item2.title}}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import Header from '../components/header.vue';
import {
ref,
reactive,
watch,
computed,
getCurrentInstance,
onMounted
} from 'vue';
const _this = getCurrentInstance();
const data = reactive({
list: [],
column: 2,
columnSpace: 1,
});
// 数据赋值
data.list = [{
image: 'https://via.placeholder.com/200x500.png/ff0000',
title: '我是标题1',
desc: '描述描述描述描述描述描述描述描述1'
},
{
image: 'https://via.placeholder.com/200x200.png/2878ff',
title: '我是标题2',
desc: '描述描述描述描述描述描述描述描述2'
},
{
image: 'https://via.placeholder.com/200x100.png/FFB6C1',
title: '我是标题3',
desc: '描述描述描述描述描述描述描述描述3'
},
{
image: 'https://via.placeholder.com/200x300.png/9400D3',
title: '我是标题4',
desc: '描述描述描述描述描述描述描述描述4'
},
{
image: 'https://via.placeholder.com/100x240.png/B0E0E6',
title: '我是标题5',
desc: '描述描述描述描述描述描述描述描述5'
},
{
image: 'https://via.placeholder.com/140x280.png/7FFFAA',
title: '我是标题6',
desc: '描述描述描述描述描述描述描述描述6'
},
{
image: 'https://via.placeholder.com/40x60.png/EEE8AA',
title: '我是标题7',
desc: '描述描述描述描述描述描述描述描述7'
},
{
image: 'https://via.placeholder.com/200x500.png/ff0000',
title: '我是标题1',
desc: '描述描述描述描述描述描述描述描述1'
},
{
image: 'https://via.placeholder.com/200x200.png/2878ff',
title: '我是标题2',
desc: '描述描述描述描述描述描述描述描述2'
},
{
image: 'https://via.placeholder.com/200x100.png/FFB6C1',
title: '我是标题3',
desc: '描述描述描述描述描述描述描述描述3'
},
{
image: 'https://via.placeholder.com/200x300.png/9400D3',
title: '我是标题4',
desc: '描述描述描述描述描述描述描述描述4'
},
{
image: 'https://via.placeholder.com/100x240.png/B0E0E6',
title: '我是标题5',
desc: '描述描述描述描述描述描述描述描述5'
},
{
image: 'https://via.placeholder.com/140x280.png/7FFFAA',
title: '我是标题6',
desc: '描述描述描述描述描述描述描述描述6'
},
{
image: 'https://via.placeholder.com/40x60.png/EEE8AA',
title: '我是标题7',
desc: '描述描述描述描述描述描述描述描述7'
},
];
// 计算列宽
const w = computed(() => {
const column_rate = `${100 / data.column - (+data.columnSpace)}%`;
return column_rate;
})
// 计算margin
const m = computed(() => {
const column_margin =
`${(100-(100 / data.column - (+data.columnSpace)).toFixed(5)*data.column)/(data.column-1)}%`;
return column_margin;
})
// 每列的数据初始化
for (let i = 1; i <= data.column; i++) {
data[`column_${i}`] = [];
}
// 获取最小值的对象
const getMin = (a, s) => {
let m = a[0][s];
let mo = a[0];
for (var i = a.length - 1; i >= 0; i--) {
if (a[i][s] < m) {
m = a[i][s];
}
}
mo = a.filter(i => i[s] == m);
return mo[0];
}
// 计算每列的高度
function getMinColumnHeight() {
return new Promise(resolve => {
const heightArr = [];
for (let i = 1; i <= data.column; i++) {
const query = uni.createSelectorQuery().in(_this);
query.select(`#waterfalls_flow_column_${i}`).boundingClientRect(data => {
heightArr.push({
column: i,
height: data.height
});
}).exec(() => {
if (data.column <= heightArr.length) {
resolve(getMin(heightArr, 'height'));
}
});
}
})
};
async function initValue(i) {
if (i >= data.list.length) return false;
const minHeightRes = await getMinColumnHeight();
data[`column_${minHeightRes.column}`].push({
...data.list[i],
index: i
});
}
onMounted(() => {
initValue(0);
})
// 图片加载完成
function imgLoad(item) {
const i = item.index;
initValue(i + 1);
}
// 图片加载失败
function imgError(item) {
const i = item.index;
initValue(i + 1);
}
</script>
<style scoped lang="scss">
.container {
background-color: rgb(237, 239, 246);
height: 100%;
}
.sticky-pos {
position: sticky;
top: 0;
z-index: 9;
background-color: rgb(237, 239, 246);
padding-bottom: 30rpx;
}
.waterfalls-flow {
padding-top: 50rpx;
&-column {
float: left;
padding: 0 0 200rpx;
}
}
.column-value {
width: 100%;
}
.imgsty {
width: 100%
}
</style>
免责声明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络收集整理,如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!
如若转载,请注明出处:https://www.zxperson.com/261.html