help-choose.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view class="flex-common-css iPhone-bottom box-border-box">
  3. <Nav :title="school_name"></Nav>
  4. <image class="bg-img" src="/pages-takeout/static/bg.png" mode=""></image>
  5. <view class="q-box z-2" ref="qBox">
  6. <view v-for="(ball,index) in shopData" :key="index" class="ball flex-direction"
  7. :style="{ left: ball.x + 'rpx', top: ball.y + 'rpx' }">
  8. <image class="qp-img" src="/pages-takeout/static/qp.png" mode=""></image>
  9. <image class="shop-logo z-2 b-rad-20" :src="ball.shop_logo" mode=""></image>
  10. <view class="fs-24 fc-f z-2 text-overflow-ellipsis-one max-w-118 text-align-center">
  11. {{ball.shop_name}}
  12. </view>
  13. </view>
  14. </view>
  15. <view class="but-box">
  16. <image class="but-img" src="/pages-takeout/static/but-bg.png" mode=""></image>
  17. <view class="fs-38 fc-f fw-b text-align-center z-2 pt-49">
  18. 君子帮你选,今日吃点啥?
  19. </view>
  20. </view>
  21. <view class="fs-28 fc-1089D1 text-align-center">
  22. 全部商家随机抽取
  23. </view>
  24. </view>
  25. </template>
  26. <script>
  27. import {
  28. shopAll
  29. } from "@/api/shop.js";
  30. export default {
  31. components: {},
  32. data() {
  33. return {
  34. school_name: '',
  35. shopId: 0,
  36. shopData: [],
  37. animationFrameId: null,
  38. animations: []
  39. };
  40. },
  41. onLoad(data) {
  42. this.school_name = uni.getStorageSync('school_name');
  43. this.getQBoxSize();
  44. },
  45. mounted() {
  46. this.shopAll();
  47. this.startAnimation();
  48. },
  49. methods: {
  50. scrolltolower() {
  51. console.log('触底');
  52. },
  53. shopAll() {
  54. shopAll().then((res) => {
  55. if (res.code === 1) {
  56. this.shopData = res.data;
  57. this.shopData.forEach((v, k) => {
  58. const radius = 59; // 小球半径相关大小(这里用宽度等体现,单位rpx)
  59. const x = Math.random() * (this.containerWidth - 2 * radius) + radius;
  60. const y = Math.random() * (this.containerHeight - 2 * radius) + radius;
  61. const speedX = (Math.random() - 0.5) * 5; // 随机生成x方向速度
  62. const speedY = (Math.random() - 0.5) * 5; // 随机生成y方向速度
  63. v.x = x;
  64. v.y = y;
  65. v.speedX = speedX;
  66. v.speedY = speedY;
  67. // 为每个小球创建动画实例
  68. const animation = uni.createAnimation({
  69. duration: 0,
  70. timingFunction: 'linear'
  71. });
  72. this.animations.push(animation);
  73. v.animation = animation;
  74. });
  75. // console.log(this.shopData);
  76. }
  77. });
  78. },
  79. startAnimation() {
  80. const animate = () => {
  81. this.updateBalls();
  82. this.animationFrameId = setTimeout(animate, 16); // 确保正确调用 animate 函数
  83. };
  84. animate();
  85. },
  86. updateBalls() {
  87. for (const ball of this.shopData) {
  88. // 更新小球位置
  89. ball.x += ball.speedX;
  90. ball.y += ball.speedY;
  91. // console.log(`Ball position: x=${ball.x}, y=${ball.y}`); // 打印小球位置信息
  92. // 处理左右边界碰撞
  93. if (ball.x < 0 || ball.x + 2 * 59 > this.containerWidth) {
  94. if (ball.x < 0) {
  95. ball.x = 0;
  96. ball.speedX = Math.abs(ball.speedX);
  97. } else {
  98. ball.x = this.containerWidth - 2 * 59;
  99. ball.speedX = -Math.abs(ball.speedX);
  100. }
  101. }
  102. // 处理上下边界碰撞
  103. if (ball.y < 0 || ball.y + 2 * 59 > this.containerHeight) {
  104. if (ball.y < 0) {
  105. ball.y = 0;
  106. ball.speedY = Math.abs(ball.speedY);
  107. } else {
  108. ball.y = this.containerHeight - 2 * 59;
  109. ball.speedY = -Math.abs(ball.speedY);
  110. }
  111. }
  112. // 使用动画更新小球位置
  113. ball.animation.translateX(ball.x).translateY(ball.y).step();
  114. ball.animation.export();
  115. // 直接使用 uni 的动画更新方法
  116. uni.createSelectorQuery().in(this).select(`.ball:nth-child(${ball.index + 1})`).boundingClientRect(
  117. rect => {
  118. if (rect) {
  119. ball.animation.export()
  120. .translate(ball.x - rect.left, ball.y - rect.top)
  121. .step()
  122. .update();
  123. }
  124. }).exec();
  125. }
  126. // 利用 Vue 的响应式数据绑定自动更新视图,不再使用 $forceUpdate
  127. },
  128. getQBoxSize() {
  129. uni.createSelectorQuery().in(this).select('.q-box').boundingClientRect((rect) => {
  130. if (rect) {
  131. this.containerWidth = (rect.width) * 2;
  132. this.containerHeight = (rect.height) * 2;
  133. }
  134. }).exec();
  135. }
  136. },
  137. beforeDestroy() {
  138. // 清除定时器
  139. clearTimeout(this.animationFrameId);
  140. }
  141. }
  142. </script>
  143. <style lang="scss" scoped>
  144. .max-w-118{
  145. max-width: 118rpx;
  146. }
  147. .qp-box-ccc {
  148. background: #ccc;
  149. }
  150. .z-2 {
  151. position: relative;
  152. z-index: 2;
  153. }
  154. .q-box {
  155. width: 100%;
  156. height: 71%;
  157. padding-bottom: constant(safe-area-inset-bottom);
  158. padding-bottom: env(safe-area-inset-bottom);
  159. position: relative;
  160. }
  161. .ball {
  162. width: 118rpx;
  163. height: 154rpx;
  164. position: absolute;
  165. padding-top: 28rpx;
  166. }
  167. .shop-logo {
  168. width: 68.5rpx;
  169. height: 68.5rpx;
  170. margin: 0 0 34rpx 29rpx;
  171. }
  172. .bg-img {
  173. width: 100%;
  174. height: 89%;
  175. position: absolute;
  176. left: 0;
  177. top: 0;
  178. }
  179. .but-box {
  180. width: 100%;
  181. height: 170rpx;
  182. position: relative;
  183. }
  184. .but-img {
  185. position: absolute;
  186. left: 0;
  187. top: 0;
  188. width: 100%;
  189. height: 100%;
  190. }
  191. .pt-49 {
  192. padding-top: 49rpx;
  193. }
  194. .qp-img {
  195. width: 118rpx;
  196. height: 118rpx;
  197. position: absolute;
  198. left: 0;
  199. top: 0;
  200. }
  201. </style>