vue实现转盘抽奖
实现思路
Vue实现转盘抽奖的核心是通过CSS动画控制转盘旋转,结合Vue的数据绑定和计算属性动态控制旋转角度和结果判定。关键点包括转盘布局、动画触发、结果计算和回调处理。
转盘布局设计
使用CSS绘制转盘扇形区域,每个奖项对应一个扇形。通过Vue动态绑定样式,根据奖项数量计算每个扇形的旋转角度。
<template>
<div class="wheel-container">
<div
class="wheel"
:style="{ transform: `rotate(${rotateDeg}deg)` }"
@transitionend="onTransitionEnd"
>
<div
v-for="(item, index) in prizeList"
:key="index"
class="sector"
:style="getSectorStyle(index)"
>
{{ item.name }}
</div>
</div>
<button @click="startRotate">开始抽奖</button>
</div>
</template>
动画逻辑实现
通过修改rotateDeg触发CSS过渡动画,计算最终停止角度时需考虑中奖概率和转盘惯性效果。
export default {
data() {
return {
prizeList: [
{ name: '一等奖', probability: 0.1 },
{ name: '二等奖', probability: 0.2 },
// ...其他奖项
],
rotateDeg: 0,
isRotating: false
}
},
methods: {
getSectorStyle(index) {
const angle = 360 / this.prizeList.length
return {
transform: `rotate(${angle * index}deg)`,
'background-color': `hsl(${index * (360 / this.prizeList.length)}, 70%, 60%)`
}
},
startRotate() {
if (this.isRotating) return
this.isRotating = true
// 随机选择奖项(可根据probability加权)
const prizeIndex = Math.floor(Math.random() * this.prizeList.length)
// 计算旋转角度(多转几圈后停在目标位置)
const sectorAngle = 360 / this.prizeList.length
this.rotateDeg += 360 * 10 + (360 - (sectorAngle * prizeIndex))
},
onTransitionEnd() {
this.isRotating = false
// 获取最终奖项逻辑
const normalizedDeg = this.rotateDeg % 360
const sectorAngle = 360 / this.prizeList.length
const prizeIndex = Math.floor((360 - normalizedDeg) / sectorAngle) % this.prizeList.length
console.log('中奖:', this.prizeList[prizeIndex])
}
}
}
CSS样式设计
关键样式包括转盘容器定位、扇形区域计算和过渡动画设置。
.wheel-container {
position: relative;
width: 300px;
height: 300px;
margin: 0 auto;
}
.wheel {
width: 100%;
height: 100%;
border-radius: 50%;
position: relative;
transition: transform 4s cubic-bezier(0.17, 0.67, 0.21, 0.99);
transform: rotate(0deg);
}
.sector {
position: absolute;
width: 50%;
height: 50%;
left: 0;
top: 0;
transform-origin: right bottom;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
概率控制优化
实际项目中需要根据后台配置的概率进行加权随机,以下为概率计算示例:
function getWeightedRandom(prizeList) {
const sum = prizeList.reduce((acc, cur) => acc + cur.probability, 0)
let random = Math.random() * sum
for (let i = 0; i < prizeList.length; i++) {
if (random < prizeList[i].probability) return i
random -= prizeList[i].probability
}
return prizeList.length - 1
}
注意事项
- 转盘旋转角度计算需要考虑初始位置和多次旋转的累积角度
- 过渡动画结束事件
transitionend需要处理兼容性问题 - 移动端可能需要添加
touchstart事件支持 - 实际项目中建议将动画逻辑封装为独立组件
- 中奖概率建议由后端接口返回,避免前端被篡改







