waterfall.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <route lang="json5" type="page">
  2. {
  3. style: { navigationBarTitleText: 'waterfall' },
  4. }
  5. </route>
  6. <template>
  7. <view class="waterfall">
  8. <uv-waterfall
  9. ref="waterfall"
  10. v-model="list"
  11. :add-time="10"
  12. :left-gap="leftGap"
  13. :right-gap="rightGap"
  14. :column-gap="columnGap"
  15. @changeList="changeList"
  16. >
  17. <!-- 第一列数据 -->
  18. <template v-slot:list1>
  19. <!-- 为了磨平部分平台的BUG,必须套一层view -->
  20. <view>
  21. <view v-for="item in lists.list1" :key="item.id" class="waterfall-item">
  22. <view class="waterfall-item__image" :style="[imageStyle(item)]">
  23. <image
  24. :src="item.image"
  25. mode="widthFix"
  26. :style="{ width: item.width + 'px' }"
  27. ></image>
  28. </view>
  29. <view class="waterfall-item__ft">
  30. <view class="waterfall-item__ft__title">
  31. <text class="value">{{ item.title }}</text>
  32. </view>
  33. <view class="waterfall-item__ft__desc uv-line-2">
  34. <text class="value">{{ item.desc }}</text>
  35. </view>
  36. </view>
  37. </view>
  38. </view>
  39. </template>
  40. <!-- 第二列数据 -->
  41. <template v-slot:list2>
  42. <!-- 为了磨平部分平台的BUG,必须套一层view -->
  43. <view>
  44. <view v-for="item in lists.list2" :key="item.id" class="waterfall-item">
  45. <view class="waterfall-item__image" :style="[imageStyle(item)]">
  46. <image
  47. :src="item.image"
  48. mode="widthFix"
  49. :style="{ width: item.width + 'px' }"
  50. ></image>
  51. </view>
  52. <view class="waterfall-item__ft">
  53. <view class="waterfall-item__ft__title">
  54. <text class="value">{{ item.title }}</text>
  55. </view>
  56. <view class="waterfall-item__ft__desc uv-line-2">
  57. <text class="value">{{ item.desc }}</text>
  58. </view>
  59. </view>
  60. </view>
  61. </view>
  62. </template>
  63. </uv-waterfall>
  64. </view>
  65. </template>
  66. <script lang="ts" setup>
  67. // eslint-disable-next-line import/extensions
  68. import { guid } from '@climblee/uv-ui/libs/function/index.js'
  69. const list = ref([]) // 瀑布流全部数据
  70. const lists = reactive({
  71. list1: [], // 瀑布流第一列数据
  72. list2: [], // 瀑布流第二列数据
  73. })
  74. const leftGap = ref(10)
  75. const rightGap = ref(10)
  76. const columnGap = ref(10)
  77. const imageStyle = computed(() => {
  78. return (item) => {
  79. const v = uni.upx2px(750) - leftGap.value - rightGap.value - columnGap.value
  80. const w = v / 2
  81. const rate = w / item.w
  82. const h = rate * item.h
  83. return {
  84. width: `${w}px`,
  85. height: `${h}px`,
  86. }
  87. }
  88. })
  89. onLoad(async () => {
  90. const { data } = await getData()
  91. list.value = data
  92. })
  93. const waterfall = ref()
  94. // 如果页面还没渲染结束,页面就跳走,但此时@changeList回调还在返回数据,可能会造成渲染出错,所以要想办法停止渲染
  95. onHide(() => {
  96. waterfall.value.clear()
  97. })
  98. // 这点非常重要:e.name在这里返回是list1或list2,要手动将数据追加到相应列
  99. const changeList = (e: { name: 'list1' | 'list2'; value: any }) => {
  100. lists[e.name].push(e.value)
  101. }
  102. // 模拟的后端数据6
  103. const getData = (): Promise<{ data: any[] }> => {
  104. return new Promise((resolve) => {
  105. const imgs = [
  106. { url: 'https://via.placeholder.com/100x110.png/3c9cff/fff', width: 100, height: 110 },
  107. { url: 'https://via.placeholder.com/200x220.png/f9ae3d/fff', width: 200, height: 220 },
  108. { url: 'https://via.placeholder.com/300x340.png/5ac725/fff', width: 300, height: 340 },
  109. { url: 'https://via.placeholder.com/400x400.png/f56c6c/fff', width: 400, height: 400 },
  110. { url: 'https://via.placeholder.com/500x510.png/909399/fff', width: 500, height: 510 },
  111. { url: 'https://via.placeholder.com/600x606.png/3c9cff/fff', width: 600, height: 606 },
  112. { url: 'https://via.placeholder.com/310x422.png/f1a532/fff', width: 310, height: 422 },
  113. { url: 'https://via.placeholder.com/320x430.png/3c9cff/fff', width: 320, height: 430 },
  114. { url: 'https://via.placeholder.com/330x424.png/f9ae3d/fff', width: 330, height: 424 },
  115. { url: 'https://via.placeholder.com/340x435.png/5ac725/fff', width: 340, height: 435 },
  116. { url: 'https://via.placeholder.com/350x440.png/f56c6c/fff', width: 350, height: 440 },
  117. { url: 'https://via.placeholder.com/380x470.png/909399/fff', width: 380, height: 470 },
  118. ]
  119. const arr = []
  120. const doFn = (i: number) => {
  121. const randomIndex = Math.floor(Math.random() * 10)
  122. return {
  123. id: guid(),
  124. allowEdit: i === 0,
  125. image: imgs[randomIndex].url,
  126. w: imgs[randomIndex].width,
  127. h: imgs[randomIndex].height,
  128. title:
  129. i % 2 === 0
  130. ? `(${list.value.length + i + 1})体验uv-ui框架`
  131. : `(${list.value.length + i + 1})uv-ui支持多平台`,
  132. desc:
  133. i % 2 === 0
  134. ? `(${list.value.length + i + 1})欢迎使用uv-ui,uni-app生态专用的UI框架`
  135. : `(${list.value.length + i})开发者编写一套代码, 可发布到iOS、Android、H5、以及各种小程序`,
  136. }
  137. }
  138. // 模拟异步
  139. setTimeout(() => {
  140. for (let i = 0; i < 20; i++) {
  141. arr.push(doFn(i))
  142. }
  143. resolve({ data: arr })
  144. }, 200)
  145. })
  146. }
  147. </script>
  148. <style>
  149. page {
  150. background: #f1f1f1;
  151. }
  152. </style>
  153. <style lang="scss" scoped>
  154. .waterfall-item {
  155. margin-top: 10px;
  156. overflow: hidden;
  157. border-radius: 6px;
  158. /* stylelint-disable-next-line selector-class-pattern */
  159. .waterfall-item__ft {
  160. padding: 20rpx;
  161. background: #fff;
  162. &__title {
  163. margin-bottom: 10rpx;
  164. font-weight: 700;
  165. line-height: 48rpx;
  166. .value {
  167. font-size: 32rpx;
  168. color: #303133;
  169. }
  170. }
  171. &__desc .value {
  172. font-size: 28rpx;
  173. color: #606266;
  174. }
  175. &__btn {
  176. padding: 10px 0;
  177. }
  178. }
  179. }
  180. </style>