新增组件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}// 如果这个图片已经在加载中,返回现有的 promiseif (pendingImages.value.has(item.image)) {return pendingImages.value.get(item.image)}const promise = new Promise((resolveImage) => {uni.getImageInfo({src: item.image,success: (res) => {// 保存图片的实际尺寸信息到 itemitem.imageWidth = res.widthitem.imageHeight = res.heightpendingImages.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) returnconst item = tempList.value[0]if (!item) returntry {// 等待图片预加载完成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}])