Files
ks-app-employment-service/uni_modules/custom-waterfalls-flow/components/custom-waterfalls-flow/custom-waterfalls-flow.vue
2025-10-24 17:37:38 +08:00

369 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="waterfalls-flow">
<view
v-for="(item, index) in data.column"
:key="index"
class="waterfalls-flow-column"
:id="`waterfalls_flow_column_${index + 1}`"
:msg="msg"
:style="{ width: w, 'margin-left': index == 0 ? 0 : m }"
>
<view
:class="['column-value', { 'column-value-show': item2.o }]"
v-for="(item2, index2) in columnValue(index)"
:key="index2"
:style="[s1]"
@click.stop="wapperClick(item2)"
>
<view class="inner" v-if="data.seat == 1">
<!-- #ifdef MP-WEIXIN -->
<!-- #ifdef VUE2 -->
<slot name="slot{{item2.index}}"></slot>
<!-- #endif -->
<!-- #ifdef VUE3 -->
<slot :name="`slot${item2.index}`"></slot>
<!-- #endif -->
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<slot v-bind="item2"></slot>
<!-- #endif -->
</view>
<image
:class="[
'img',
{ 'img-hide': item2[hideImageKey] == true || item2[hideImageKey] == 1 },
{ 'img-error': !item2[data.imageKey] },
]"
:src="item2[data.imageKey]"
mode="widthFix"
@load="imgLoad(item2, index + 1)"
@error="imgError(item2, index + 1)"
@click.stop="imageClick(item2)"
></image>
<view class="inner" v-if="data.seat == 2">
<!-- #ifdef MP-WEIXIN -->
<!-- #ifdef VUE2 -->
<slot name="slot{{item2.index}}"></slot>
<!-- #endif -->
<!-- #ifdef VUE3 -->
<slot :name="`slot${item2.index}`"></slot>
<!-- #endif -->
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<slot v-bind="item2"></slot>
<!-- #endif -->
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
value: Array,
column: {
// 列的数量
type: [String, Number],
default: 2,
},
maxColumn: {
// 最大列数
type: [String, Number],
default: 5,
},
columnSpace: {
// 列之间的间距 百分比
type: [String, Number],
default: 2,
},
imageKey: {
// 图片key
type: [String],
default: 'image',
},
hideImageKey: {
// 隐藏图片key
type: [String],
default: 'hide',
},
seat: {
// 文本的位置1图片之上 2图片之下
type: [String, Number],
default: 2,
},
listStyle: {
// 单个展示项的样式eg:{'background':'red'}
type: Object,
},
},
data() {
return {
data: {
list: this.value ? this.value : [],
column: this.column < 2 ? 2 : this.column,
columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
imageKey: this.imageKey,
seat: this.seat,
},
msg: 0,
listInitStyle: {
'border-radius': '12rpx',
'margin-bottom': '20rpx',
'background-color': '#fff',
},
adds: [], //预置数据
isLoaded: true,
curIndex: 0,
isRefresh: true,
flag: false,
refreshDatas: [],
};
},
computed: {
// 计算列宽
w() {
const column_rate = `${100 / this.data.column - +this.data.columnSpace}%`;
return column_rate;
},
// 计算margin
m() {
const column_margin = `${
(100 - (100 / this.data.column - +this.data.columnSpace).toFixed(5) * this.data.column) /
(this.data.column - 1)
}%`;
return column_margin;
},
// list样式
s1() {
return { ...this.listInitStyle, ...this.listStyle };
},
},
created() {
// 初始化
this.refresh();
},
methods: {
// 预加载图片
loadImages(idx = 0) {
let count = 0;
const newList = this.data.list.filter((item, index) => index >= idx);
for (let i = 0; i < newList.length; i++) {
// #ifndef APP-PLUS
uni.getImageInfo({
src: `${newList[i][this.imageKey]}.jpg`,
complete: (res) => {
count++;
if (count == newList.length) this.initValue(idx);
},
});
// #endif
// #ifdef APP-PLUS
plus.io.getImageInfo({
src: `${newList[i][this.imageKey]}.jpg`,
complete: (res) => {
count++;
if (count == newList.length) this.initValue(idx);
},
});
// #endif
}
},
// 刷新
refresh() {
if (!this.isLoaded) {
this.refreshDatas = this.value;
return false;
}
setTimeout(() => {
this.refreshDatas = [];
this.isRefresh = true;
this.adds = [];
this.data.list = this.value ? this.value : [];
this.data.column = this.column < 2 ? 2 : this.column >= this.maxColumn ? this.maxColumn : this.column;
this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5;
this.data.imageKey = this.imageKey;
this.data.seat = this.seat;
this.curIndex = 0;
// 每列的数据初始化
for (let i = 1; i <= this.data.column; i++) {
this.data[`column_${i}_values`] = [];
this.msg++;
}
this.$nextTick(() => {
this.initValue(this.curIndex, 'refresh==>');
});
}, 1);
},
columnValue(index) {
return this.data[`column_${index + 1}_values`];
},
change(newValue) {
for (let i = 0; i < this.data.list.length; i++) {
const cv = this.data[`column_${this.data.list[i].column}_values`];
for (let j = 0; j < cv.length; j++) {
if (newValue[i] && i === cv[j].index) {
this.data[`column_${this.data.list[i].column}_values`][j] = Object.assign(cv[j], newValue[i]);
this.msg++;
break;
}
}
}
},
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];
},
// 计算每列的高度
getMinColumnHeight() {
return new Promise((resolve) => {
const heightArr = [];
for (let i = 1; i <= this.data.column; i++) {
const query = uni.createSelectorQuery().in(this);
query
.select(`#waterfalls_flow_column_${i}`)
.boundingClientRect((data) => {
// 添加 null 检查,防止 data 为 null 时访问 height 属性
if (data && data.height !== undefined) {
heightArr.push({ column: i, height: data.height });
} else {
// 如果元素不存在或高度未定义,使用默认高度 0
heightArr.push({ column: i, height: 0 });
}
})
.exec(() => {
if (this.data.column <= heightArr.length) {
resolve(this.getMin(heightArr, 'height'));
}
});
}
});
},
async initValue(i, from) {
this.isLoaded = false;
if (i >= this.data.list.length || this.refreshDatas.length) {
this.msg++;
this.loaded();
return false;
}
const minHeightRes = await this.getMinColumnHeight();
const c = this.data[`column_${minHeightRes.column}_values`];
this.data.list[i].column = minHeightRes.column;
c.push({ ...this.data.list[i], cIndex: c.length, index: i, o: 0 });
this.msg++;
},
// 图片加载完成
imgLoad(item, c) {
const i = item.index;
item.o = 1;
this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
this.initValue(i + 1);
},
// 图片加载失败
imgError(item, c) {
const i = item.index;
item.o = 1;
item[this.data.imageKey] = null;
this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
this.initValue(i + 1);
},
// 渲染结束
loaded() {
if (this.refreshDatas.length) {
this.isLoaded = true;
this.refresh();
return false;
}
this.curIndex = this.data.list.length;
if (this.adds.length) {
this.data.list = this.adds[0];
this.adds.splice(0, 1);
this.initValue(this.curIndex);
} else {
if (this.data.list.length) this.$emit('loaded');
this.isLoaded = true;
this.isRefresh = false;
}
},
// 单项点击事件
wapperClick(item) {
this.$emit('wapperClick', item);
},
// 图片点击事件
imageClick(item) {
this.$emit('imageClick', item);
},
},
watch: {
value: {
deep: true,
handler(newValue, oldValue) {
setTimeout(() => {
this.$nextTick(() => {
if (this.isRefresh) return false;
if (this.isLoaded) {
// if (newValue.length <= this.curIndex) return this.refresh();
if (newValue.length <= this.curIndex) return this.change(newValue);
this.data.list = newValue;
this.$nextTick(() => {
this.initValue(this.curIndex, 'watch==>');
});
} else {
this.adds.push(newValue);
}
});
}, 10);
},
},
column(newValue) {
this.refresh();
},
},
};
</script>
<style lang="scss" scoped>
.waterfalls-flow {
overflow: hidden;
&-column {
float: left;
}
}
.column-value {
width: 100%;
font-size: 0;
overflow: hidden;
transition: opacity 0.4s;
opacity: 0;
&-show {
opacity: 1;
}
.inner {
font-size: 30rpx;
}
.img {
width: 100%;
&-hide {
display: none;
}
&-error {
background: #f2f2f2
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAiAQMAAAAatXkPAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAAIZJREFUCNdlzjEKwkAUBNAfEGyCuYBkLyLuxRYW2SKlV1JSeA2tUiZg4YrLjv9PGsHqNTPMSAQuyAJgRDHSyvBPwtZoSJXakeJI9iuRLGDygdl6V0yKDtyMAeMPZySj8yfD+UapvRPj2JOwkyAooSV5IwdDjPdCPspe8LyTl9IKJvDETKKRv6vnlUasgg0fAAAAAElFTkSuQmCC)
no-repeat center center;
}
}
}
</style>