新增组件m-waterfall 这样就可以在页面直接使用 不用在引入了
<template>
<view class="m-waterfall">
<view id="m-left-column" class="m-column">
<slot name="left" :leftList="leftList"></slot>
</view>
<view id="m-right-column" class="m-column">
<slot name="right" :rightList="rightList"></slot>
</view>
</view>
</template>
<script setup>
/**
* @param value 瀑布流数据
* @param addTime 插入数据的时间间隔
* @param keyIdData / id值,用于清除某一条数据时,根据此idKey名称找到并移除
*/
import {
computed,
defineProps,
toRefs
} from "vue"
const props=defineProps({
// 瀑布流数据
value: {
required: true,
type: Array,
default: ()=>[]
},
// 每次向结构插入数据的时间间隔,间隔越长,越能保证两列高度相近,但是对用户体验越不好
addTime: {
type: [Number, String],
default: 200
},
// id值,用于清除某一条数据时,根据此idKey名称找到并移除
keyIdData: {
type: String,
default: 'id'
}
})
const {
value,
addTime,
keyIdData
} = toRefs(props)
const leftList = ref([])
const rightList = ref([])
const tempList = ref([])
const pendingImages = ref(new Map()) // 用于追踪待加载的图片
const copyFlowList= computed (()=> {
return cloneData(value.value);
})
// 记录正在加载的图片数量
const loadingCount = ref(0)
// 处理图片加载完成事件
const preloadImage = async (item) => {
return new Promise((resolve) => {
if (!item.image) {
resolve(item)
return
}
// 如果这个图片已经在加载中,返回现有的 promise
if (pendingImages.value.has(item.image)) {
return pendingImages.value.get(item.image)
}
const promise = new Promise((resolveImage) => {
uni.getImageInfo({
src: item.image,
success: (res) => {
// 保存图片的实际尺寸信息到 item
item.imageWidth = res.width
item.imageHeight = res.height
pendingImages.value.delete(item.image)
resolveImage(item)
},
fail: () => {
pendingImages.value.delete(item.image)
resolveImage(item)
}
})
})
pendingImages.value.set(item.image, promise)
resolve(promise)
})
}
// const emit=defineEmits(['handleImageLoad'])
watch(()=>value.value,(nVal,oVal)=>{
let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0;
tempList.value = tempList.value.concat(cloneData(nVal.slice(startIndex)));
splitData();
})
onMounted(()=>{
tempList.value = cloneData(copyFlowList.value);
setTimeout(()=>{
splitData();
},200)
})
const instance = getCurrentInstance()
const getColumnHeight = (columnId) => {
return new Promise((resolve) => {
uni.createSelectorQuery()
.in(instance)
.select(columnId)
.boundingClientRect(data => {
resolve(data ? data.height : 0)
})
.exec()
})
}
const splitData = async () => {
if (tempList.value.length === 0) return
const item = tempList.value[0]
if (!item) return
try {
// 等待图片预加载完成
await preloadImage(item)
// 获取两列的高度
const [leftHeight, rightHeight] = await Promise.all([
getColumnHeight('#m-left-column'),
getColumnHeight('#m-right-column')
])
// 根据高度决定放入哪一列
if (leftHeight <= rightHeight) {
leftList.value.push(item)
} else {
rightList.value.push(item)
}
// 移除已处理的项目
tempList.value.splice(0, 1)
// 继续处理下一个项目
if (tempList.value.length) {
setTimeout(() => {
splitData()
}, Number(props.addTime))
}
} catch (error) {
console.error('Error in splitData:', error)
// 发生错误时也移除当前项目,继续处理下一个
tempList.value.splice(0, 1)
if (tempList.value.length) {
splitData()
}
}
}
// 复制而不是引用对象和数组
const cloneData=(data)=>{
if(data){
return JSON.parse(JSON.stringify(data));
}else{
return [];
}
}
</script>
<style lang="scss" scoped>
.m-waterfall {
margin-top: 20rpx;
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 10rpx;
}
.m-column {
display: flex;
flex: 1;
flex-direction: column;
height: auto;
}
.m-image {
width: 100%;
}
</style>
组件使用
<m-waterfall :value="product">
<!-- 左边数据 -->
<template v-slot:left="{leftList}">
<view @click="addDta" class="prodecutitem" v-for="(item,index) in leftList" :key="index">
<view style="width: 100%;">
<m-imgage :url="item.image"></m-imgage>
</view>
<view class="title">{{item.title}}</view>
<view class="desc">{{item.title}}</view>
</view>
</template>
<!-- 右边数据 -->
<template v-slot:right="{rightList}">
<view class="prodecutitem" v-for="(item,index) in rightList" :key="index">
<view>
<m-imgage :url="item.image"></m-imgage>
</view>
<view class="title">{{item.title}}</view>
<view class="desc">{{item.title}}</view>
</view>
</template>
</m-waterfal>
数据
const product=ref([
{
title:'水果蔬菜1',
image:imgSrc.value
},
{
title:'水果蔬菜2',
image:"https://img2.baidu.com/it/u=3893165480,918722033&fm=253&fmt=auto&app=120&f=JPEG?w=729&h=1215"
},
{
title:'水果蔬菜3',
image:imgSrc.value
},
{
title:'水果蔬菜1',
image:imgSrc.value
},
{
title:'水果蔬菜3',
image:imgSrc.value
}
])