1212.vue 7.2 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="https://sjz-school.oss-cn-chengdu.aliyuncs.com/webImages/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. // 生成更大的速度,范围在 -5 到 5 之间,使小球移动更快
  62. const speedX = (Math.random() - 0.5) * 5;
  63. const speedY = (Math.random() - 0.5) * 5;
  64. v.x = x;
  65. v.y = y;
  66. v.speedX = speedX;
  67. v.speedY = speedY;
  68. // 为每个小球创建动画实例
  69. const animation = uni.createAnimation({
  70. duration: 0,
  71. timingFunction: 'linear'
  72. });
  73. this.animations.push(animation);
  74. v.animation = animation;
  75. });
  76. // console.log(this.shopData);
  77. }
  78. });
  79. },
  80. startAnimation() {
  81. const animate = () => {
  82. this.updateBalls();
  83. // 进一步减小调用间隔,例如 20 毫秒,提高更新频率
  84. this.animationFrameId = setTimeout(animate, 20);
  85. };
  86. animate();
  87. },
  88. updateBalls() {
  89. for (const ball of this.shopData) {
  90. // 更新小球位置
  91. ball.x += ball.speedX;
  92. ball.y += ball.speedY;
  93. // 处理左右边界碰撞
  94. if (ball.x < 0 || ball.x + 2 * 59 > this.containerWidth) {
  95. if (ball.x < 0) {
  96. ball.x = 0;
  97. ball.speedX = Math.abs(ball.speedX);
  98. } else {
  99. ball.x = this.containerWidth - 2 * 59;
  100. ball.speedX = -Math.abs(ball.speedX);
  101. }
  102. }
  103. // 处理上下边界碰撞
  104. if (ball.y < 0 || ball.y + 2 * 59 > this.containerHeight) {
  105. if (ball.y < 0) {
  106. ball.y = 0;
  107. ball.speedY = Math.abs(ball.speedY);
  108. } else {
  109. ball.y = this.containerHeight - 2 * 59;
  110. ball.speedY = -Math.abs(ball.speedY);
  111. }
  112. }
  113. // 使用动画更新小球位置
  114. ball.animation.translateX(ball.x).translateY(ball.y).step();
  115. ball.animation.export();
  116. // 直接使用 uni 的动画更新方法
  117. uni.createSelectorQuery().in(this).select(`.ball:nth-child(${ball.index + 1})`).boundingClientRect(
  118. rect => {
  119. if (rect) {
  120. ball.animation.export()
  121. .translate(ball.x - rect.left, ball.y - rect.top)
  122. .step()
  123. .update();
  124. }
  125. }).exec();
  126. }
  127. // 利用 Vue 的响应式数据绑定自动更新视图,不再使用 $forceUpdate
  128. },
  129. getQBoxSize() {
  130. uni.createSelectorQuery().in(this).select('.q-box').boundingClientRect((rect) => {
  131. if (rect) {
  132. this.containerWidth = (rect.width) * 2;
  133. this.containerHeight = (rect.height) * 2;
  134. }
  135. }).exec();
  136. }
  137. },
  138. beforeDestroy() {
  139. // 清除定时器
  140. clearTimeout(this.animationFrameId);
  141. }
  142. }
  143. </script>
  144. <style lang="scss" scoped>
  145. .max-w-118{
  146. max-width: 118rpx;
  147. }
  148. .qp-box-ccc {
  149. background: #ccc;
  150. }
  151. .z-2 {
  152. position: relative;
  153. z-index: 2;
  154. }
  155. .q-box {
  156. width: 100%;
  157. height: 71%;
  158. padding-bottom: constant(safe-area-inset-bottom);
  159. padding-bottom: env(safe-area-inset-bottom);
  160. position: relative;
  161. }
  162. .ball {
  163. width: 118rpx;
  164. height: 154rpx;
  165. position: absolute;
  166. padding-top: 28rpx;
  167. }
  168. .shop-logo {
  169. width: 68.5rpx;
  170. height: 68.5rpx;
  171. margin: 0 0 34rpx 29rpx;
  172. }
  173. .bg-img {
  174. width: 100%;
  175. height: 89%;
  176. position: absolute;
  177. left: 0;
  178. top: 0;
  179. }
  180. .but-box {
  181. width: 100%;
  182. height: 170rpx;
  183. position: relative;
  184. }
  185. .but-img {
  186. position: absolute;
  187. left: 0;
  188. top: 0;
  189. width: 100%;
  190. height: 100%;
  191. }
  192. .pt-49 {
  193. padding-top: 49rpx;
  194. }
  195. .qp-img {
  196. width: 118rpx;
  197. height: 118rpx;
  198. position: absolute;
  199. left: 0;
  200. top: 0;
  201. }
  202. </style>