zw-waterfall.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <template>
  2. <view class="waterfall-box">
  3. <view class="waterfall-left">
  4. <!-- <view v-for="(item,index) in leftList" :key="item._render_id"
  5. class="list-item"
  6. :class="{'show': showPage > item._current_page }"
  7. >
  8. <helang-waterfall-item
  9. :params="item"
  10. tag="left"
  11. :index="index"
  12. @height="onHeight"
  13. @click="onClick"
  14. ></helang-waterfall-item>
  15. </view> -->
  16. </view>
  17. <view class="waterfall-right">
  18. <!-- <view v-for="(item,index) in rightList" :key="item._render_id"
  19. class="list-item"
  20. :class="{'show': showPage > item._current_page }"
  21. >
  22. <helang-waterfall-item
  23. :params="item"
  24. @height="onHeight"
  25. @click="onClick"
  26. tag="right"
  27. :index="index"
  28. ></helang-waterfall-item>
  29. </view> -->
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. // import helangWaterfallItem from "./waterfall-item.vue"
  35. export default {
  36. name: " ",
  37. options: {
  38. virtualHost: true
  39. },
  40. // components: {
  41. // "helang-waterfall-item": helangWaterfallItem
  42. // },
  43. props: {
  44. // 组件状态
  45. // status:{
  46. // type: String,
  47. // default:''
  48. // },
  49. // 待渲染的数据
  50. list: {
  51. type: Array,
  52. default: () => {
  53. return [];
  54. }
  55. },
  56. // 重置列表,设置为 true 时,瀑布流会自动重新渲染列表
  57. // reset:{
  58. // type: Boolean,
  59. // default:false
  60. // },
  61. },
  62. data() {
  63. return {
  64. // 左侧列表高度
  65. leftHeight: 0,
  66. // 右侧列表高度
  67. rightHeight: 0,
  68. // 左侧列表数据
  69. leftList: [],
  70. // 右侧列表数据
  71. rightList: [],
  72. // 待渲染列表
  73. awaitRenderList: [],
  74. // 当前展示页码数据
  75. showPage: 1
  76. }
  77. },
  78. watch: {
  79. "list": {
  80. handler: function(newList, oldList) {
  81. if (!newList || newList.length === 0) {
  82. this.awaitRenderList = []
  83. // 左侧列表数据
  84. this.leftList = [];
  85. // 右侧列表数据
  86. this.rightList = [];
  87. } else {
  88. const RenderListLength = this.awaitRenderList.length;
  89. const arr = newList.slice(RenderListLength, newList.length);
  90. this.awaitRenderList = this.awaitRenderList.concat(arr)
  91. }
  92. },
  93. immediate: true
  94. },
  95. // "$props.status"(newValue, oldValue) {
  96. // // 状态变更为 加载成功 时,执行瀑布流数据渲染
  97. // if (newValue == 'success') {
  98. // this.startRender();
  99. // } else if (!this.showList) {
  100. // this.resetData();
  101. // }
  102. // }
  103. },
  104. computed: {
  105. // showList(){
  106. // return !["fail","empty"].includes(this.$props.status);
  107. // }
  108. },
  109. mounted() {
  110. if (this.$props.status == 'success') {
  111. this.startRender();
  112. }
  113. },
  114. methods: {
  115. // 监听高度变化
  116. onHeight(height, tag) {
  117. /**
  118. * 这个为实际渲染后 CSS 中 margin-buttom 的值,本示例默认为20rpx
  119. * 用于解决实际渲染后因为数据条数关系,高度差计算偏差的问题
  120. * */
  121. let marginBottom = uni.upx2px(20);
  122. // console.log(`左高:${this.leftHeight},右高:${this.rightHeight},当前高:${height},插入方向:${tag}`)
  123. if (tag == 'left') {
  124. this.leftHeight += (height + marginBottom);
  125. } else {
  126. this.rightHeight += (height + marginBottom);
  127. }
  128. this.renderList();
  129. },
  130. // 组件点击事件
  131. onClick(index, tag) {
  132. // 对应的数据
  133. if (tag == 'left') {
  134. this.$emit("click", this.leftList[index], index, tag);
  135. } else {
  136. this.$emit("click", this.rightList[index], index, tag);
  137. }
  138. },
  139. // 渲染列表,这里实现瀑布流的左右分栏
  140. renderList() {
  141. // 待渲染长度为 0 时表示已渲染完成
  142. if (this.awaitRenderList.length < 1) {
  143. this.showPage++;
  144. this.$emit("done");
  145. // 为防止 js 数值类型最大值溢出,当高度值大于 1亿时重置高度
  146. if (this.leftHeight > 100000000) {
  147. if (this.leftHeight > this.rightHeight) {
  148. this.leftHeight = 2;
  149. this.rightHeight = 1;
  150. } else {
  151. this.leftHeight = 1;
  152. this.rightHeight = 2;
  153. }
  154. }
  155. return;
  156. }
  157. let item = {
  158. ...this.awaitRenderList.splice(0, 1)[0],
  159. // 当前数据添加当前页面标识
  160. _current_page: this.showPage,
  161. // 当前数据添加一个渲染id,解决 v-for 重复会出现不执行 load 的 BUG
  162. _render_id: new Date().getTime()
  163. };
  164. if (this.leftHeight > this.rightHeight) {
  165. this.rightList.push(item);
  166. } else {
  167. this.leftList.push(item);
  168. }
  169. },
  170. // 重置数据
  171. resetData() {
  172. this.leftHeight = 0;
  173. this.rightHeight = 0;
  174. this.leftList = [];
  175. this.rightList = [];
  176. this.awaitRenderList = [];
  177. // 当前展示页码数据
  178. this.showPage = 1;
  179. },
  180. // 启动渲染
  181. startRender() {
  182. if (!this.showList) {
  183. this.resetData();
  184. return;
  185. }
  186. if (!this.$props.list || this.$props.list.length < 1) {
  187. console.log('河浪瀑布流插件提示:当前数据为空,不会触发列表渲染');
  188. return;
  189. }
  190. // 若本次渲染为 重置 则先恢复组件的默认参数
  191. if (this.$props.reset) {
  192. this.resetData();
  193. }
  194. this.awaitRenderList = [...this.$props.list];
  195. this.renderList();
  196. }
  197. }
  198. }
  199. </script>
  200. <style lang="scss" scoped>
  201. .waterfall-box {
  202. // padding: 20rpx 10rpx;
  203. // box-sizing: border-box;
  204. width: 100%;
  205. height: 1000px;
  206. display: flex;
  207. justify-content: space-between;
  208. .waterfall-left,
  209. .waterfall-right {
  210. width: calc(50% - 10rpx);
  211. height: 100%;
  212. }
  213. .waterfall-left {
  214. background-color: skyblue;
  215. }
  216. .waterfall-right {
  217. background-color: hotpink;
  218. }
  219. }
  220. </style>