vue实现红包雨
实现红包雨的基本思路
红包雨是一种常见的互动效果,通常用于节日活动或营销场景。在Vue中实现红包雨需要结合CSS动画和JavaScript逻辑。
创建红包组件
设计一个红包组件,包含图片和可能的点击事件。组件可以接收位置、速度等属性。
<template>
<div
class="red-packet"
:style="{
left: `${position.x}px`,
top: `${position.y}px`,
animationDuration: `${duration}s`
}"
@click="handleClick"
>
<img src="@/assets/red-packet.png" alt="红包">
</div>
</template>
<script>
export default {
props: {
position: {
type: Object,
required: true
},
duration: {
type: Number,
default: 5
}
},
methods: {
handleClick() {
this.$emit('click');
}
}
}
</script>
<style>
.red-packet {
position: absolute;
animation: fall linear;
cursor: pointer;
z-index: 10;
}
@keyframes fall {
to {
transform: translateY(100vh);
}
}
</style>
主容器实现
创建一个主容器组件,用于控制红包的生成和动画。
<template>
<div class="rain-container">
<RedPacket
v-for="(packet, index) in packets"
:key="index"
:position="packet.position"
:duration="packet.duration"
@click="collectPacket(index)"
/>
</div>
</template>
<script>
import RedPacket from './RedPacket.vue';
export default {
components: {
RedPacket
},
data() {
return {
packets: [],
timer: null
};
},
mounted() {
this.startRain();
},
beforeDestroy() {
this.stopRain();
},
methods: {
startRain() {
this.timer = setInterval(() => {
this.createPacket();
}, 300);
},
stopRain() {
clearInterval(this.timer);
},
createPacket() {
const packet = {
position: {
x: Math.random() * (window.innerWidth - 50),
y: -50
},
duration: 3 + Math.random() * 4
};
this.packets.push(packet);
setTimeout(() => {
this.packets = this.packets.filter(p => p !== packet);
}, packet.duration * 1000);
},
collectPacket(index) {
this.packets.splice(index, 1);
// 处理红包收集逻辑
}
}
};
</script>
<style>
.rain-container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
</style>
性能优化方案
当红包数量较多时,需要考虑性能优化。
使用requestAnimationFrame替代CSS动画
updatePosition() {
this.packets.forEach(packet => {
packet.position.y += packet.speed;
if (packet.position.y > window.innerHeight) {
this.removePacket(packet);
}
});
this.animationId = requestAnimationFrame(this.updatePosition);
}
使用对象池技术复用红包DOM
reusePacket(packet) {
packet.position.x = Math.random() * (window.innerWidth - 50);
packet.position.y = -50;
packet.speed = 2 + Math.random() * 3;
return packet;
}
高级功能扩展
添加碰撞检测
checkCollision(packet1, packet2) {
const dx = packet1.position.x - packet2.position.x;
const dy = packet1.position.y - packet2.position.y;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance < 50; // 红包直径
}
添加物理效果
applyPhysics(packet) {
packet.velocityY += 0.1; // 重力加速度
packet.position.y += packet.velocityY;
packet.position.x += packet.velocityX;
}
移动端适配
处理触摸事件
<template>
<div
class="red-packet"
@touchstart="handleTouch"
>
<!-- ... -->
</div>
</template>
<script>
methods: {
handleTouch(e) {
e.preventDefault();
this.$emit('click');
}
}
</script>
调整红包大小
.red-packet {
width: 10vw;
height: 12vw;
}
注意事项
- 动画性能监控:使用DevTools的Performance面板检测帧率
- 内存管理:及时清理不可见的红包对象
- 响应式设计:确保不同屏幕尺寸下效果一致
- 降级方案:为不支持CSS动画的浏览器提供备用方案
以上实现可以根据具体需求进行调整,如添加音效、积分系统等增强用户体验的功能。







