masonry.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /**
  2. * 瀑布流组件
  3. */
  4. Component({
  5. properties: {
  6. intervalWidth: {
  7. type: String,
  8. value: "20rpx"
  9. }
  10. },
  11. data: {
  12. items: [],
  13. stopMasonry: false
  14. },
  15. methods: {
  16. /**
  17. * 批量添加元素
  18. *
  19. * @param {Array} items - 新增的元素数组
  20. */
  21. append(items) {
  22. if (Object.prototype.toString.call(items) !=='[object Array]') {
  23. console.error("[masonry]参数类型错误,渲染失败");
  24. return false;
  25. }
  26. this.setData({
  27. stopMasonry: false
  28. })
  29. return this._refresh(items);
  30. },
  31. /**
  32. * 批量删除瀑布流中的元素
  33. *
  34. * @param {Number} start - 开始下标
  35. * @param {Number} end - 结束下标
  36. */
  37. delete(start, end) {
  38. const { items } = this.data;
  39. if (start < end && start < items.length - 1) {
  40. let len = end- start;
  41. let newItems = items.splice(start, len);
  42. this._refresh(newItems)
  43. } else {
  44. console.error("[masonry]初始下标异常,删除失败!");
  45. }
  46. },
  47. /**
  48. * 更新数组中的某个元素
  49. *
  50. * @param {Object} newItem - 修改后的元素
  51. * @param {Number} index - 需要更新的数组下标
  52. */
  53. updateItem(newItem, index) {
  54. const { items } = this.data;
  55. if (index <= items.length - 1) {
  56. this.setData({
  57. items: [
  58. ...items.slice(0, index),
  59. Object.assign(items[index], newItem),
  60. ...items.slice(index + 1)
  61. ]
  62. })
  63. } else {
  64. console.error("[masonry]下标越界,修改失败!");
  65. }
  66. },
  67. /**
  68. * 删除瀑布流中的某个元素
  69. *
  70. * @param {Number} index - 数组下标
  71. */
  72. deleteItem(index) {
  73. const { items } = this.data;
  74. if (index <= items.length - 1) {
  75. let newItems = items.splice(index, 1);
  76. this._refresh(newItems)
  77. } else {
  78. console.error("[masonry]下标越界,删除失败!");
  79. }
  80. },
  81. /**
  82. * 刷新瀑布流
  83. *
  84. * @param {Array} items - 参与渲染的元素数组
  85. */
  86. start(items) {
  87. if (Object.prototype.toString.call(items) !=='[object Array]') {
  88. console.error("[masonry]参数类型错误,渲染失败");
  89. return false;
  90. }
  91. this.setData({
  92. items: [],
  93. stopMasonry: false
  94. })
  95. return this._refresh(items);
  96. },
  97. /**
  98. * 停止渲染瀑布流
  99. */
  100. stop() {
  101. this.setData({
  102. stopMasonry: true,
  103. items: []
  104. })
  105. },
  106. /**
  107. * 刷新瀑布流
  108. *
  109. * @param {Array} items - 参与渲染的元素数组
  110. */
  111. _refresh(items) {
  112. const query = wx.createSelectorQuery().in(this)
  113. this.columnNodes = query.selectAll('#left-col-inner, #right-col-inner')
  114. return new Promise((resolve, reject) => {
  115. this._render(items, 0, () => {
  116. resolve()
  117. })
  118. })
  119. },
  120. /**
  121. * 渲染函数
  122. *
  123. * @param {Array} items - 正在渲染的数组
  124. * @param {Number} i - 当前渲染元素的下标
  125. * @param {Function} onComplete - 完成后的回调函数
  126. */
  127. _render (items, i, onComplete) {
  128. if (items.length > i && !this.data.stopMasonry) {
  129. this.columnNodes.boundingClientRect().exec(arr => {
  130. const item = items[i]
  131. const rects = arr[0]
  132. const leftColHeight = rects[0].height
  133. const rightColHeight = rects[1].height
  134. this.setData({
  135. items: [...this.data.items, {
  136. ...item,
  137. columnPosition: leftColHeight <= rightColHeight ? 'left' : 'right'
  138. }]
  139. }, () => {
  140. this._render(items, ++i, onComplete)
  141. })
  142. })
  143. } else {
  144. onComplete && onComplete()
  145. }
  146. },
  147. needAuth: function () {
  148. this.triggerEvent('needAuth');
  149. }
  150. }
  151. });