yunshangxie/tuniao-ui/components/tn-waterfall/tn-waterfall.vue

166 lines
5.2 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="tn-waterfall-class tn-waterfall">
<view id="tn-waterfall-left" class="tn-waterfall__column"><slot name="left" :leftList="leftList"></slot></view>
<view id="tn-waterfall-right" class="tn-waterfall__column"><slot name="right" :rightList="rightList"></slot></view>
</view>
</template>
<script>
export default {
name: 'tn-waterfall',
props: {
// 瀑布流数据
value: {
type: Array,
default() {
return []
}
},
// 数据的id值根据id值对数据执行删除操作
// 如数据为:{id: 1, name: 'tuniao'}那么该值设置为id
idKey: {
type: String,
default: 'id'
},
// 每次插入数据的事件间隔,间隔越长能保证两列高度相近,但是用户体验不好
// 单位ms
addTime: {
type: Number,
default: 200
}
},
computed: {
// 破坏value变量引用否则数据会保持不变
copyValue() {
return this.cloneData(this.value)
}
},
watch: {
copyValue(nVal, oVal) {
// 取出数组发生变化的部分
let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0
// 拼接原有数据
this.tempList = this.tempList.concat(this.cloneData(nVal.slice(startIndex)))
this.splitData()
}
},
data() {
return {
// 左列表
leftList: [],
// 右列表
rightList: [],
// 临时列表
tempList: []
}
},
mounted() {
this.tempList = this.cloneData(this.copyValue)
this.splitData()
},
methods: {
// 拆分数据
async splitData() {
if (!this.tempList.length) return
let leftRect = await this._tGetRect('#tn-waterfall-left')
let rightRect = await this._tGetRect('#tn-waterfall-right')
let item = this.tempList[0]
// 因为经过上面两个await节点查询和定时器数组有可能会变成空[]导致item的值为undefined
// 解决多次快速滚动会导致数据乱的问题
if (!item) return
// 如果左边小于或者等于右边,就添加到左边,否则添加到右边
if (leftRect.height < rightRect.height) {
this.leftList.push(item)
} else if (leftRect.height > rightRect.height) {
this.rightList.push(item)
} else {
// 为了保证前两项添加时,左右两边都还没有内容,这时候根据队列长度判断下一项该放在哪一边
if (this.leftList.length <= this.rightList.length) {
this.leftList.push(item)
} else {
this.rightList.push(item)
}
}
// 移除临时数组中已处理的数据
this.tempList.splice(0, 1)
// 如果还有数据则继续执行
if (this.tempList.length) {
setTimeout(() => {
this.splitData()
}, this.addTime)
} else {
this.$emit('finish')
}
},
// 复制对象和数组(深度复制不会影响原对象和数组)
cloneData(data) {
return JSON.parse(JSON.stringify(data))
},
// 清空数据列表
clear() {
this.leftList = []
this.rightList = []
this.$emit('input', [])
this.tempList = []
},
// 清除指定的某一条数据根据id来实现
remove(id) {
// 如果查找不到就返回-1
let index = -1
index = this.leftList.findIndex(val => val[this.idKey] == id)
if (index != -1) {
// 如果index不等于-1说明已经找到了指定的数据
this.leftList.splice(index, 1)
} else {
// 同理于上面的方法
index = this.rightList.findIndex(val => val[this.idKey] == id)
if (index != -1) this.rightList.splice(index, 1)
}
// 同时删除父组件对应的数据
index = this.value.findIndex(val => val[this.idKey] == id)
if (index != -1) this.$emit('input', this.value.splice(index, 1))
},
// 修改指定数据的属性
modify(id, key, value) {
// 如果查找不到就返回-1
let index = -1
index = this.leftList.findIndex(val => val[this.idKey] == id)
if (index != -1) {
// 如果index不等于-1说明已经找到了指定的数据
this.leftList[index][key] = value
} else {
// 同理于上面的方法
index = this.rightList.findIndex(val => val[this.idKey] == id)
if (index != -1) this.rightList[index][key] = value
}
// 同时删除父组件对应的数据
index = this.value.findIndex(val => val[this.idKey] == id)
if(index != -1) {
let data = this.cloneData(this.value)
data[index][key] = value
this.$emit('input', data)
}
}
}
}
</script>
<style lang="scss" scoped>
.tn-waterfall {
display: flex;
flex-direction: row;
align-items: flex-start;
&__column {
display: flex;
flex-direction: column;
flex: 1;
height: auto;
}
}
</style>