vue 实现转盘抽奖
Vue 实现转盘抽奖功能
转盘抽奖是一种常见的互动效果,可以通过 Vue 结合 CSS 动画和 JavaScript 逻辑实现。以下是一个完整的实现方案:
基础 HTML 结构
在 Vue 模板中定义转盘的基本结构:
<template>
<div class="lottery-container">
<div class="wheel" :style="wheelStyle">
<div
v-for="(item, index) in prizes"
:key="index"
class="wheel-item"
:style="getItemStyle(index)"
>
{{ item.name }}
</div>
</div>
<button @click="startLottery" :disabled="isRotating">开始抽奖</button>
</div>
</template>
CSS 样式设计
转盘的样式需要设置为圆形,每个奖项均匀分布:
<style>
.lottery-container {
position: relative;
width: 300px;
height: 300px;
margin: 0 auto;
}
.wheel {
width: 100%;
height: 100%;
border-radius: 50%;
position: relative;
overflow: hidden;
transition: transform 4s cubic-bezier(0.17, 0.67, 0.12, 0.99);
}
.wheel-item {
position: absolute;
width: 50%;
height: 50%;
transform-origin: 100% 100%;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
</style>
JavaScript 逻辑实现
在 Vue 组件中实现转盘的核心逻辑:
<script>
export default {
data() {
return {
prizes: [
{ name: '一等奖', color: '#FF0000' },
{ name: '二等奖', color: '#00FF00' },
{ name: '三等奖', color: '#0000FF' },
{ name: '四等奖', color: '#FFFF00' },
{ name: '五等奖', color: '#FF00FF' },
{ name: '六等奖', color: '#00FFFF' }
],
isRotating: false,
currentRotation: 0
}
},
computed: {
wheelStyle() {
return {
transform: `rotate(${this.currentRotation}deg)`,
background: 'conic-gradient(' +
this.prizes.map((item, i) =>
`${item.color} ${i * (360/this.prizes.length)}deg ${(i+1) * (360/this.prizes.length)}deg`
).join(', ') +
')'
}
}
},
methods: {
getItemStyle(index) {
const angle = 360 / this.prizes.length
return {
transform: `rotate(${angle * index + angle/2}deg)`,
color: this.getContrastColor(this.prizes[index].color)
}
},
getContrastColor(hexColor) {
const r = parseInt(hexColor.substr(1, 2), 16)
const g = parseInt(hexColor.substr(3, 2), 16)
const b = parseInt(hexColor.substr(5, 2), 16)
return (r * 0.299 + g * 0.587 + b * 0.114) > 186 ? '#000000' : '#FFFFFF'
},
startLottery() {
if (this.isRotating) return
this.isRotating = true
const rounds = 5 // 旋转圈数
const targetIndex = Math.floor(Math.random() * this.prizes.length)
const targetAngle = 360 - (targetIndex * (360 / this.prizes.length)) + 360 * rounds
this.currentRotation += targetAngle
setTimeout(() => {
this.isRotating = false
alert(`恭喜获得: ${this.prizes[targetIndex].name}`)
}, 4000)
}
}
}
</script>
优化方向
- 平滑停止效果:使用 CSS 的
transition-timing-function实现缓动效果 - 奖品配置化:通过 props 接收奖品列表,使组件更通用
- 响应式设计:使用 vw/vh 单位适应不同屏幕尺寸
- 音效增强:添加旋转和停止时的音效
- 结果回调:通过 emit 事件将抽奖结果传递给父组件
高级实现方案
对于更复杂的需求,可以考虑以下改进:
// 在 methods 中添加
calculateStopPosition() {
// 可以与后端交互获取真实中奖结果
return axios.get('/api/lottery').then(res => {
return res.data.prizeIndex
})
},
async startAdvancedLottery() {
if (this.isRotating) return
this.isRotating = true
const rounds = 5
const targetIndex = await this.calculateStopPosition()
const anglePerItem = 360 / this.prizes.length
const targetAngle = 360 * rounds + (360 - targetIndex * anglePerItem)
this.currentRotation = this.currentRotation % 360
this.currentRotation += targetAngle
setTimeout(() => {
this.isRotating = false
this.$emit('lottery-end', this.prizes[targetIndex])
}, 4000)
}
注意事项
- 旋转角度计算要考虑当前旋转位置
- 转盘停止位置应该指向奖品中心
- 多次快速点击需要防止重复触发
- 移动端需要考虑触摸事件支持
- 动画性能优化可使用 will-change 属性
以上实现方案提供了从基础到高级的转盘抽奖功能,可根据实际需求进行调整和扩展。







