WaterfallsFlow.vue
<template>
<view class="wf-page" :class="props?.paddingC ? 'paddingC' : ''">
<!-- left -->
<view>
<view id="left" ref="left" v-if="leftList.length">
<view
v-for="(item, index) in leftList"
:key="index"
class="wf-item"
@tap="itemTap(item)"
>
<!-- #ifdef MP-WEIXIN -->
//这里需要注意插槽id 必须是唯一id ,否则小程序显示异常
<slot :name="`slot${item.customSId || item.id}`"></slot>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<slot :item="item" :index="index"></slot>
<!-- #endif -->
<!-- <slot :item="item" :index="index"></slot> -->
</view>
</view>
</view>
<!-- right -->
<view>
<view id="right" ref="right" v-if="rightList.length">
<view
v-for="(item, index) in rightList"
:key="index"
class="wf-item"
@tap="itemTap(item)"
>
<!-- #ifdef MP-WEIXIN -->
//这里需要注意插槽id 必须是唯一id ,否则小程序显示异常
<slot :name="`slot${item.customSId || item.id}`"></slot>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<slot :item="item" :index="index"></slot>
<!-- #endif --></view
>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
// import App from "@/script/module/App.js";
import { axj } from "@/script/sdk/cloudfarm";
import {
reactive,
ref,
onMounted,
watch,
nextTick,
getCurrentInstance,
} from "vue";
import { onPageScroll, onShow, onPullDownRefresh } from "@dcloudio/uni-app";
import App from "@/script/module/App";
const props: any = defineProps({
// 瀑布流列表
wfList: {
type: Array,
require: true,
},
updateNum: {
type: Number,
default: 10,
},
updated: {
//强制页面重新渲染
type: Boolean,
default: false,
},
paddingC: {
//控制显示paddding 兼容之前瀑布流样式
type: Boolean,
default: false,
},
});
const _this = getCurrentInstance();
let allList = ref([]);
let leftList = ref([]);
let rightList = ref([]);
let boxHeight = ref([]);
let mark = ref(0);
// 调用父组件
const emits = defineEmits(["itemTap", "notify"]);
// 瀑布流排序
const waterFall = () => {
const i = mark.value;
if (i === 0) {
// 初始化,从左边开始插入
leftList.value.push(allList.value[i]);
// 更新左边列表高度
nextTick(() => {
getViewHeight(0);
});
} else if (i === 1) {
// 第二个item插入,默认为右边插入
rightList.value.push(allList.value[i]);
// 更新右边列表高度
nextTick(() => {
getViewHeight(1);
});
} else {
// 根据左右列表高度判断下一个item应该插入哪边
const leftOrRight = boxHeight.value[0] >= boxHeight.value[1] ? 1 : 0;
if (leftOrRight) {
rightList.value.push(allList.value[i]);
} else {
leftList.value.push(allList.value[i]);
}
// 更新插入列表高度 setTimeout用来解决 多次数据push 计算高度错误问题
setTimeout(() => {
getViewHeight(leftOrRight);
}, 0);
}
};
// 获取列表高度
const getViewHeight = (leftOrRight) => {
const query = uni.createSelectorQuery().in(this || _this);
const id = leftOrRight ? "#right" : "#left";
// 使用nextTick,确保页面更新结束后,再请求高度
nextTick(() => {
query
.select(id)
.boundingClientRect((res: any) => {
res ? (boxHeight.value[leftOrRight] = res.height) : "";
mark.value = mark.value + 1;
})
.exec();
});
};
// item点击
const itemTap = (item) => {
emits("itemTap", item);
};
const setWfList = (wfList) => {
allList.value = wfList;
waterFall();
};
let collect = () => {
let requestParm = {
topicModule: props?.topicModule,
topicId: props?.topicId,
};
return new Promise((resolve, reject) => {
App.client?.farm.Api_UserInteract.thumb(0, [requestParm], (err, res) => {
if (res) {
resolve(true);
}
});
});
};
watch(
() => props.wfList,
() => {
// 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
if (
!props.wfList.length ||
(props.wfList.length === props.updateNum &&
props.wfList.length <= allList.value.length) ||
props.updated
) {
allList.value = [];
leftList.value = [];
rightList.value = [];
boxHeight.value = [];
mark.value = 0;
}
// 如果列表有值,调用waterfall方法
if (props.wfList.length) {
allList.value = props.wfList;
waterFall();
}
},
{
immediate: true, // 初始化数据触发watch
// deep: true, // 对 对象进行深度监听 ; 此处深度监听,如果数据改变(比如点赞)会导致页面重绘
}
);
watch(
() => mark.value,
() => {
const len = allList.value.length;
if (mark.value < len && mark.value !== 0) {
waterFall();
} else {
if (boxHeight.value.length >= 2) {
let bHeight =
boxHeight.value[0] > boxHeight.value[1]
? boxHeight.value[0]
: boxHeight.value[1];
emits("notify", bHeight);
}
}
},
{
immediate: true, // 初始化数据触发watch
deep: true, // 对 对象进行深度监听
}
);
</script>
<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: $grid-gap;
// padding: 10px $page-padding;
}
.paddingC {
padding: 10px $page-padding;
}
.wf-item {
width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
padding-bottom: $grid-gap;
}
</style>
waterfall.vue
//这里需要注意customSId 必须是唯一id ,否则小程序显示异常
<template>
<WaterfallsFlow ref="wfListRef" :wfList="DataList" :updated="updated">
<!-- #ifdef MP-WEIXIN -->
<view
class="item"
v-for="(item, index) in DataList"
:key="index"
:slot="`slot${item.customSId}`"
>
//这里自己写插槽内容
<view :item="item" ></view>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<template v-slot="{ item }">
<view class="item">
//这里自己写插槽内容
<view :item="item" ></view>
</view>
</template>
<!-- #endif -->
</WaterfallsFlow>
</template>
<script lang="ts" setup >
import { reactive, ref, onMounted, watch } from "vue";
import { onPageScroll, onShow, onPullDownRefresh } from "@dcloudio/uni-app";
import WaterfallsFlow from "./WaterfallsFlow.vue";
const DataList = ref([
{
image:
"https://ss.dev.yiyiny.com/digital/2023/04/25/00yqnc0wglmzhtqf.jpg?x-oss-process=image/quality,q_50",
avatar:
"https://cdn.pixabay.com/user/2015/10/12/02-06-28-605_250x250.jpg",
nickName: 1,
title:
"非常好看的额图片,快起来这里买看的额图片,快起来这里买看的额图片,快起来这里买看的额图片,快起来这里买东西",
isLike: true,
},
{
image:
"https://ss.dev.yiyiny.com/digital/2023/04/24/009vus6uglv9477m.jpeg?x-oss-process=image/quality,q_5",
avatar:
"https://cdn.pixabay.com/user/2015/10/12/02-06-28-605_250x250.jpg",
nickName: 2,
title: "这段文字要少",
isLike: false,
},
];)
</script>
<style scoped lang="scss">
</style>