tn-waterfall.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <template>
  2. <view class="tn-waterfall-class tn-waterfall">
  3. <view id="tn-waterfall-left" class="tn-waterfall__column"><slot name="left" :leftList="leftList"></slot></view>
  4. <view id="tn-waterfall-right" class="tn-waterfall__column"><slot name="right" :rightList="rightList"></slot></view>
  5. </view>
  6. </template>
  7. <script>
  8. export default {
  9. name: 'tn-waterfall',
  10. props: {
  11. // 瀑布流数据
  12. value: {
  13. type: Array,
  14. default() {
  15. return []
  16. }
  17. },
  18. // 数据的id值,根据id值对数据执行删除操作
  19. // 如数据为:{id: 1, name: 'tuniao'},那么该值设置为id
  20. idKey: {
  21. type: String,
  22. default: 'id'
  23. },
  24. // 每次插入数据的事件间隔,间隔越长能保证两列高度相近,但是用户体验不好
  25. // 单位ms
  26. addTime: {
  27. type: Number,
  28. default: 200
  29. }
  30. },
  31. computed: {
  32. // 破坏value变量引用,否则数据会保持不变
  33. copyValue() {
  34. return this.cloneData(this.value)
  35. }
  36. },
  37. watch: {
  38. copyValue(nVal, oVal) {
  39. // 取出数组发生变化的部分
  40. let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0
  41. // 拼接原有数据
  42. this.tempList = this.tempList.concat(this.cloneData(nVal.slice(startIndex)))
  43. this.splitData()
  44. }
  45. },
  46. data() {
  47. return {
  48. // 左列表
  49. leftList: [],
  50. // 右列表
  51. rightList: [],
  52. // 临时列表
  53. tempList: []
  54. }
  55. },
  56. mounted() {
  57. this.tempList = this.cloneData(this.copyValue)
  58. this.splitData()
  59. },
  60. methods: {
  61. // 拆分数据
  62. async splitData() {
  63. if (!this.tempList.length) return
  64. let leftRect = await this._tGetRect('#tn-waterfall-left')
  65. let rightRect = await this._tGetRect('#tn-waterfall-right')
  66. let item = this.tempList[0]
  67. // 因为经过上面两个await节点查询和定时器,数组有可能会变成空[],导致item的值为undefined
  68. // 解决多次快速滚动会导致数据乱的问题
  69. if (!item) return
  70. // 如果左边小于或者等于右边,就添加到左边,否则添加到右边
  71. if (leftRect.height < rightRect.height) {
  72. this.leftList.push(item)
  73. } else if (leftRect.height > rightRect.height) {
  74. this.rightList.push(item)
  75. } else {
  76. // 为了保证前两项添加时,左右两边都还没有内容,这时候根据队列长度判断下一项该放在哪一边
  77. if (this.leftList.length <= this.rightList.length) {
  78. this.leftList.push(item)
  79. } else {
  80. this.rightList.push(item)
  81. }
  82. }
  83. // 移除临时数组中已处理的数据
  84. this.tempList.splice(0, 1)
  85. // 如果还有数据则继续执行
  86. if (this.tempList.length) {
  87. setTimeout(() => {
  88. this.splitData()
  89. }, this.addTime)
  90. } else {
  91. this.$emit('finish')
  92. }
  93. },
  94. // 复制对象和数组(深度复制不会影响原对象和数组)
  95. cloneData(data) {
  96. return JSON.parse(JSON.stringify(data))
  97. },
  98. // 清空数据列表
  99. clear() {
  100. this.leftList = []
  101. this.rightList = []
  102. this.$emit('input', [])
  103. this.tempList = []
  104. },
  105. // 清除指定的某一条数据,根据id来实现
  106. remove(id) {
  107. // 如果查找不到就返回-1
  108. let index = -1
  109. index = this.leftList.findIndex(val => val[this.idKey] == id)
  110. if (index != -1) {
  111. // 如果index不等于-1,说明已经找到了指定的数据
  112. this.leftList.splice(index, 1)
  113. } else {
  114. // 同理于上面的方法
  115. index = this.rightList.findIndex(val => val[this.idKey] == id)
  116. if (index != -1) this.rightList.splice(index, 1)
  117. }
  118. // 同时删除父组件对应的数据
  119. index = this.value.findIndex(val => val[this.idKey] == id)
  120. if (index != -1) this.$emit('input', this.value.splice(index, 1))
  121. },
  122. // 修改指定数据的属性
  123. modify(id, key, value) {
  124. // 如果查找不到就返回-1
  125. let index = -1
  126. index = this.leftList.findIndex(val => val[this.idKey] == id)
  127. if (index != -1) {
  128. // 如果index不等于-1,说明已经找到了指定的数据
  129. this.leftList[index][key] = value
  130. } else {
  131. // 同理于上面的方法
  132. index = this.rightList.findIndex(val => val[this.idKey] == id)
  133. if (index != -1) this.rightList[index][key] = value
  134. }
  135. // 同时删除父组件对应的数据
  136. index = this.value.findIndex(val => val[this.idKey] == id)
  137. if(index != -1) {
  138. let data = this.cloneData(this.value)
  139. data[index][key] = value
  140. this.$emit('input', data)
  141. }
  142. }
  143. }
  144. }
  145. </script>
  146. <style lang="scss" scoped>
  147. .tn-waterfall {
  148. display: flex;
  149. flex-direction: row;
  150. align-items: flex-start;
  151. &__column {
  152. display: flex;
  153. flex-direction: column;
  154. flex: 1;
  155. height: auto;
  156. }
  157. }
  158. </style>