vue实现点击红包雨
Vue 实现点击红包雨效果
实现红包雨效果需要结合 Vue 的响应式数据绑定和动画效果。以下是具体实现方法:
创建红包组件
定义一个红包组件,包含红包图片和点击事件处理逻辑。可以使用 v-for 动态生成多个红包。
<template>
<div
class="red-packet"
v-for="(packet, index) in packets"
:key="index"
:style="{
left: packet.left + 'px',
top: packet.top + 'px',
animation: `fall ${packet.duration}s linear infinite`
}"
@click="collectPacket(index)"
>
<img src="@/assets/red-packet.png" alt="红包">
</div>
</template>
<script>
export default {
data() {
return {
packets: []
}
},
methods: {
collectPacket(index) {
this.packets.splice(index, 1)
// 处理收集红包逻辑
}
}
}
</script>
添加红包雨动画
使用 CSS 动画实现红包下落效果。定义 fall 动画让红包从顶部移动到底部。

.red-packet {
position: absolute;
width: 50px;
height: 60px;
cursor: pointer;
z-index: 100;
}
@keyframes fall {
from {
transform: translateY(-100px);
}
to {
transform: translateY(100vh);
}
}
控制红包生成
在 Vue 组件中设置定时器,定期生成新的红包并随机设置位置和下落速度。
export default {
mounted() {
this.startRain()
},
methods: {
startRain() {
setInterval(() => {
if (this.packets.length < 20) { // 控制最大红包数量
this.packets.push({
left: Math.random() * window.innerWidth,
top: -60,
duration: 3 + Math.random() * 5 // 随机下落速度
})
}
}, 300) // 每300毫秒生成一个红包
}
}
}
优化性能
对于大量红包元素,可以使用 Vue 的 v-show 替代 v-if 减少 DOM 操作,或者使用虚拟滚动技术优化性能。

<template>
<div
class="red-packet"
v-for="(packet, index) in packets"
:key="index"
v-show="packet.visible"
>
<!-- 红包内容 -->
</div>
</template>
添加点击效果
为增强用户体验,可以在点击红包时添加动画效果或音效。
methods: {
collectPacket(index) {
this.packets[index].visible = false
// 播放收集音效
const audio = new Audio('collect-sound.mp3')
audio.play()
// 显示收集动画
this.showCollectionEffect(this.packets[index])
}
}
响应式调整
监听窗口大小变化,调整红包位置和动画参数。
mounted() {
window.addEventListener('resize', this.adjustPackets)
},
beforeDestroy() {
window.removeEventListener('resize', this.adjustPackets)
},
methods: {
adjustPackets() {
this.packets = this.packets.map(packet => ({
...packet,
left: Math.random() * window.innerWidth
}))
}
}
完整示例
<template>
<div class="red-packet-container">
<div
class="red-packet"
v-for="(packet, index) in packets"
:key="index"
:style="packetStyle(packet)"
@click="collectPacket(index)"
>
<img src="@/assets/red-packet.png" alt="红包">
</div>
</div>
</template>
<script>
export default {
data() {
return {
packets: [],
maxPackets: 20
}
},
mounted() {
this.startRain()
window.addEventListener('resize', this.adjustPackets)
},
beforeDestroy() {
clearInterval(this.rainInterval)
window.removeEventListener('resize', this.adjustPackets)
},
methods: {
packetStyle(packet) {
return {
left: packet.left + 'px',
top: packet.top + 'px',
animation: `fall ${packet.duration}s linear infinite`,
opacity: packet.visible ? 1 : 0
}
},
startRain() {
this.rainInterval = setInterval(() => {
if (this.packets.length < this.maxPackets) {
this.packets.push({
left: Math.random() * window.innerWidth,
top: -60,
duration: 3 + Math.random() * 5,
visible: true
})
}
}, 300)
},
collectPacket(index) {
this.packets[index].visible = false
setTimeout(() => {
this.packets.splice(index, 1)
}, 500)
},
adjustPackets() {
this.packets = this.packets.map(packet => ({
...packet,
left: Math.min(packet.left, window.innerWidth - 50)
}))
}
}
}
</script>
<style>
.red-packet-container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.red-packet {
position: absolute;
width: 50px;
height: 60px;
cursor: pointer;
z-index: 100;
transition: opacity 0.3s;
}
@keyframes fall {
from {
transform: translateY(-100px);
}
to {
transform: translateY(100vh);
}
}
</style>






