1212.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. <template>
  2. <view class="container">
  3. <view
  4. v-for="(ball, index) in balls"
  5. :key="index"
  6. :class="['ball', ball.colorClass]"
  7. :style="ball.style"
  8. @animationend="handleAnimationEnd(index)"
  9. >
  10. <text>{{ ball.content }}</text>
  11. </view>
  12. </view>
  13. </template>
  14. <script>
  15. export default {
  16. data() {
  17. return {
  18. balls: [], // 存储小球信息的数组
  19. animationFrames: [], // 存储每个小球的动画帧信息
  20. };
  21. },
  22. mounted() {
  23. this.initBalls();
  24. this.startAnimations();
  25. },
  26. methods: {
  27. initBalls() {
  28. const numBalls = 10; // 小球数量
  29. for (let i = 0; i < numBalls; i++) {
  30. this.balls.push({
  31. colorClass: this.getRandomColorClass(), // 随机颜色类
  32. content: `Ball ${i + 1}`, // 自定义内容
  33. style: {
  34. position: 'absolute',
  35. left: `${Math.random() * window.innerWidth}px`, // 随机初始位置X
  36. top: `${Math.random() * window.innerHeight}px`, // 随机初始位置Y
  37. transform: `translate(-50%, -50%)`, // 居中内容
  38. },
  39. direction: { x: Math.random() * 2 - 1, y: Math.random() * 2 - 1 }, // 随机方向
  40. speed: Math.random() * 2 + 1, // 随机速度
  41. });
  42. }
  43. },
  44. getRandomColorClass() {
  45. // 根据需要返回随机颜色类名,这里简化为几个预设类
  46. const colors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange'];
  47. return colors[Math.floor(Math.random() * colors.length)];
  48. },
  49. startAnimations() {
  50. // 为每个小球启动动画
  51. this.balls.forEach((ball, index) => {
  52. setTimeout(() => {
  53. this.animateBall(index);
  54. }, Math.random() * 2000); // 随机延迟开始动画
  55. });
  56. },
  57. animateBall(index) {
  58. const ball = this.balls[index];
  59. let newLeft = parseFloat(ball.style.left) + ball.direction.x * ball.speed;
  60. let newTop = parseFloat(ball.style.top) + ball.direction.y * ball.speed;
  61. // 碰撞检测(边界反弹)
  62. if (newLeft < 0 || newLeft > window.innerWidth - 50) { // 50是假设的小球宽度
  63. ball.direction.x = -ball.direction.x;
  64. newLeft += ball.direction.x * ball.speed * 2; // 反弹后调整位置,避免抖动
  65. }
  66. if (newTop < 0 || newTop > window.innerHeight - 50) { // 50是假设的小球高度
  67. ball.direction.y = -ball.direction.y;
  68. newTop += ball.direction.y * ball.speed * 2; // 反弹后调整位置,避免抖动
  69. }
  70. ball.style.left = `${newLeft}px`;
  71. ball.style.top = `${newTop}px`;
  72. // 使用requestAnimationFrame进行持续动画
  73. this.animationFrames[index] = requestAnimationFrame(() => {
  74. this.animateBall(index);
  75. });
  76. // 可选:为动画添加结束处理(例如,当小球需要停止或改变方向时)
  77. // 但在这个例子中,我们让小球持续运动,所以不需要特别处理动画结束
  78. },
  79. handleAnimationEnd(index) {
  80. // 这个方法在这个例子中未使用,因为我们是用requestAnimationFrame控制的动画
  81. // 如果你使用CSS动画,这个方法可以用来处理动画结束后的逻辑
  82. },
  83. },
  84. beforeDestroy() {
  85. // 组件销毁前取消所有动画帧请求
  86. this.animationFrames.forEach(cancelAnimationFrame);
  87. },
  88. };
  89. </script>