Vue 3 实现转盘抽奖效果
🎡 使用 Vue 3 实现转盘抽奖效果
在移动端或营销活动中,转盘抽奖是一种非常常见的互动方式。本文基于 Vue 3 + TypeScript 实现一个视觉炫酷、逻辑完整的转盘抽奖功能,并支持「指定奖品必中」的逻辑。
iShot_2025-05-12_11.31.27
🧰 技术栈
- Vue 3 + Composition API
- CSS3 动画(transform + transition)
- 响应式布局适配(vw)
✨ 功能特性
- 转盘顺滑旋转抽奖
- 奖品可配置(支持设置指定中奖项)
- 用户抽奖次数控制
- 动画完成后触发中奖提示
- 响应式适配设计稿
🧱 页面结构拆解
以 LandComponent.vue
为例,核心结构如下:
<!-- 顶部装饰图 -->
<div class="top-img" /><!-- 抽奖区域 -->
<div class="land"><img class="背景图1" /><img class="背景图2" /><!-- 转盘区域 --><div class="prize-list" ref="prizeWrap"><divclass="prize-item"v-for="(item, index) in prizeList":style="prizeStyle(index)"><p class="text" :class="index === 0 ? 'vertical-text' : ''">{{ item.name }}</p></div></div><!-- 抽奖按钮 --><div class="btn" @click="start" /><!-- 抽奖次数提示 --><div>Você ainda tem {{ drawsNum }} tentativa</div><!-- 点击领奖按钮 --><div class="receive-btn" @click="start">Clique para Ganhar</div>
</div>
🧮 奖品配置与位置布局
奖品列表
const prizeList = ref([{ name: 'Rec.100=200', type: 1 }, // 必中项{ name: '10R$ de Recarga' },{ name: 'Não Ganhou desta Vez' },{ name: '50R$ de Recarga' },{ name: '1R$ de Recarga' },{ name: '20R$ de Recarga' },{ name: 'Não Ganhou desta Vez' },
])
奖品在圆盘上的旋转角度
const priceDeg = 15 // 空出顶部角度
const rotateAngle = computed(() => (360 - priceDeg) / (prizeList.value.length - 1))
奖品布局样式
const prizeStyle = computed(() => {const angle = rotateAngle.valuereturn (i: number) => {return i === 0? `transform: rotate(51deg); ...` // 顶部中奖项: `transform: rotate(${angle * i + angle / 2 + 5}deg); ...`}
})
🎬 抽奖动画控制
旋转总角度计算
const baseRunAngle = ref(360 * 5) // 5 需要转几圈
const totalRunAngle = computed(() => {return baseRunAngle.value + 360 - prizeId.value * rotateAngle.value - rotateAngle.value / 2 - 25
})
抽奖触发逻辑
const start = () => {if (!isRunning.value) {isRunning.value = trueprizeId.value = getRandomNum() // 决定中奖项startRun()}
}
设置旋转动画并监听结束
const startRun = () => {prizeWrap.value.style = `transform: rotate(${totalRunAngle.value}deg);transition: all 5s ease;`prizeWrap.value.addEventListener('transitionend', stopRun)
}
🎯 必中指定奖品逻辑
const getRandomNum = () => {return prizeList.value.findIndex(item => item.type === 1)
}
这段逻辑确保总是命中 type === 1 的奖品。
🛑 抽奖结束处理
const stopRun = () => {isRunning.value = falseprizeWrap.value.style = `transform: rotate(${${totalRunAngle.value - baseRunAngle.value}}deg)`setTimeout(() => {// 弹窗展示结果}, 1500)
}
📱 响应式适配
项目中使用设计稿宽度为 750px,通过以下函数将 px 转为 vw:
const pxToVw = (px: number) => (px / 750) * 100 + 'vw'
用于所有动态布局计算。
🎨 样式与动画
.prize-list {background: url('转盘背景图') no-repeat center/100% 100%;border-radius: 50%;
}
.btn {background: url('按钮图') no-repeat center/100% 100%;
}
.vertical-text {writing-mode: sideways-rl;text-orientation: upright;
}
✅ 总结
本文完整实现了一个移动端转盘抽奖功能,具备以下特点:
功能 | 说明 |
---|---|
动画 | 使用 transform + transition 平滑旋转 |
奖品布局 | 等分角度 + 计算偏移 |
指定奖品必中 | 支持自定义中奖逻辑 |
转盘视觉高度还原 | 结合背景图和动画优化 |
📚 参考资料
- Vue 3 Composition API
- MDN transform
- CSS 动画与旋转指南