1
Huangxiaoqiang-03
2024-11-11 d100db102ded4dc2047f1b92f4ed0ed4c18d8ee4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<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>