210 lines
4.6 KiB
Vue
210 lines
4.6 KiB
Vue
|
<template>
|
|||
|
<view>
|
|||
|
<view class="waterfall-box h-flex-x h-flex-2">
|
|||
|
<view>
|
|||
|
<view v-for="(item,index) in leftList" :key="item._render_id"
|
|||
|
class="list-item"
|
|||
|
:class="{'show': showPage > item._current_page }"
|
|||
|
>
|
|||
|
<!-- <slot name="slot{{item.index}}"></slot> -->
|
|||
|
<slot :item="item"></slot>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
<view>
|
|||
|
<view v-for="(item,index) in rightList" :key="item._render_id"
|
|||
|
class="list-item"
|
|||
|
:class="{'show': showPage > item._current_page }"
|
|||
|
>
|
|||
|
<!-- <slot name="slot{{item.index}}"></slot> -->
|
|||
|
<slot :item="item"></slot>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
export default {
|
|||
|
name:"helangWaterfallList",
|
|||
|
options:{
|
|||
|
virtualHost: true
|
|||
|
},
|
|||
|
props:{
|
|||
|
// 待渲染的数据
|
|||
|
list:{
|
|||
|
type: Array,
|
|||
|
default(){
|
|||
|
return [];
|
|||
|
}
|
|||
|
},
|
|||
|
// 重置列表,设置为 true 时,瀑布流会自动重新渲染列表
|
|||
|
reset:{
|
|||
|
type: Boolean,
|
|||
|
default:false
|
|||
|
},
|
|||
|
},
|
|||
|
watch:{
|
|||
|
list() {
|
|||
|
this.list.map((item,idx) => {
|
|||
|
item.index = idx
|
|||
|
return item
|
|||
|
})
|
|||
|
}
|
|||
|
},
|
|||
|
computed:{
|
|||
|
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
// 左侧列表高度
|
|||
|
leftHeight: 0,
|
|||
|
// 右侧列表高度
|
|||
|
rightHeight: 0,
|
|||
|
// 左侧列表数据
|
|||
|
leftList: [],
|
|||
|
// 右侧列表数据
|
|||
|
rightList: [],
|
|||
|
// 待渲染列表
|
|||
|
awaitRenderList:[],
|
|||
|
// 当前展示页码数据
|
|||
|
showPage:1
|
|||
|
}
|
|||
|
},
|
|||
|
mounted() {
|
|||
|
let that = this
|
|||
|
setTimeout(() => {
|
|||
|
that.startRender();
|
|||
|
},500)
|
|||
|
},
|
|||
|
methods: {
|
|||
|
// 监听高度变化
|
|||
|
onHeight(height, tag) {
|
|||
|
/**
|
|||
|
* 这个为实际渲染后 CSS 中 margin-buttom 的值,本示例默认为20rpx
|
|||
|
* 用于解决实际渲染后因为数据条数关系,高度差计算偏差的问题
|
|||
|
* */
|
|||
|
let marginBottom = uni.upx2px(20);
|
|||
|
|
|||
|
// console.log(`左高:${this.leftHeight},右高:${this.rightHeight},当前高:${height},插入方向:${tag}`)
|
|||
|
|
|||
|
if (tag == 'left') {
|
|||
|
this.leftHeight += (height + marginBottom);
|
|||
|
} else {
|
|||
|
this.rightHeight += (height + marginBottom);
|
|||
|
}
|
|||
|
this.renderList();
|
|||
|
},
|
|||
|
// 组件点击事件
|
|||
|
onClick(index, tag){
|
|||
|
// 对应的数据
|
|||
|
if(tag == 'left'){
|
|||
|
this.$emit("click",this.leftList[index],index,tag);
|
|||
|
}else{
|
|||
|
this.$emit("click",this.rightList[index],index,tag);
|
|||
|
}
|
|||
|
},
|
|||
|
// 渲染列表,这里实现瀑布流的左右分栏
|
|||
|
renderList() {
|
|||
|
// 待渲染长度为 0 时表示已渲染完成
|
|||
|
if(this.awaitRenderList.length < 1){
|
|||
|
this.showPage++;
|
|||
|
this.$emit("done");
|
|||
|
|
|||
|
// 为防止 js 数值类型最大值溢出,当高度值大于 1亿时重置高度
|
|||
|
if(this.leftHeight > 100000000){
|
|||
|
if(this.leftHeight > this.rightHeight){
|
|||
|
this.leftHeight = 2;
|
|||
|
this.rightHeight = 1;
|
|||
|
}else{
|
|||
|
this.leftHeight = 1;
|
|||
|
this.rightHeight = 2;
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
let item = {
|
|||
|
...this.awaitRenderList.splice(0,1)[0],
|
|||
|
// 当前数据添加当前页面标识
|
|||
|
_current_page:this.showPage,
|
|||
|
// 当前数据添加一个渲染id,解决 v-for 重复会出现不执行 load 的 BUG
|
|||
|
_render_id:new Date().getTime()
|
|||
|
};
|
|||
|
|
|||
|
if(this.leftHeight > this.rightHeight){
|
|||
|
this.rightList.push(item);
|
|||
|
}else{
|
|||
|
this.leftList.push(item);
|
|||
|
}
|
|||
|
},
|
|||
|
// 重置数据
|
|||
|
resetData(){
|
|||
|
this.leftHeight = 0;
|
|||
|
this.rightHeight = 0;
|
|||
|
this.leftList = [];
|
|||
|
this.rightList = [];
|
|||
|
this.awaitRenderList = [];
|
|||
|
// 当前展示页码数据
|
|||
|
this.showPage = 1;
|
|||
|
},
|
|||
|
// 启动渲染
|
|||
|
startRender(){
|
|||
|
console.log(this.list);
|
|||
|
if(!this.$props.list || this.$props.list.length < 1){
|
|||
|
console.log('河浪瀑布流插件提示:当前数据为空,不会触发列表渲染');
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 若本次渲染为 重置 则先恢复组件的默认参数
|
|||
|
if(this.$props.reset){
|
|||
|
this.resetData();
|
|||
|
}
|
|||
|
|
|||
|
this.awaitRenderList = [...this.$props.list];
|
|||
|
this.renderList();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.waterfall-box {
|
|||
|
padding: 20rpx 10rpx;
|
|||
|
box-sizing: border-box;
|
|||
|
|
|||
|
>view {
|
|||
|
padding: 0 10rpx;
|
|||
|
}
|
|||
|
|
|||
|
.list-item{
|
|||
|
margin-bottom: 0;
|
|||
|
// 设置透明,默认是可视的
|
|||
|
opacity: 0;
|
|||
|
// 默认超出隐藏,不影响加载中的文字显示效果
|
|||
|
overflow: hidden;
|
|||
|
height: 0;
|
|||
|
|
|||
|
&.show{
|
|||
|
margin-bottom: 20rpx;
|
|||
|
opacity: 1;
|
|||
|
overflow: auto;
|
|||
|
height: auto;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.h-flex-x {
|
|||
|
display: flex;
|
|||
|
flex-direction: row;
|
|||
|
flex-wrap: nowrap;
|
|||
|
justify-content: flex-start;
|
|||
|
align-items: flex-start;
|
|||
|
align-content: flex-start;
|
|||
|
|
|||
|
&.h-flex-2 {
|
|||
|
>view {
|
|||
|
width: 50%;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|