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">
    <div
      class="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.value
  return (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 = true
    prizeId.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 = false
  prizeWrap.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 平滑旋转
奖品布局等分角度 + 计算偏移
指定奖品必中支持自定义中奖逻辑
转盘视觉高度还原结合背景图和动画优化

📚 参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值