实现转盘抽奖功能

1、实现转盘数据动态配置(可通过接口获取)

2、背景色通过分隔配置

3、转动速度慢慢减速,最后停留在每一项的中间,下一次开始从本次开始

4、当动画停止后在对应事件中自定义生成中奖提示。

5、本次中奖概率随机生成,也可自定义配置

实现代码

html

js 复制代码
<template>
  <div class="graph-page">
    <div class="plate-wrapper" :style="`${bgColor};`">
      <div class="item-plate" :style="plateCss(index)" v-for="(item, index) in plateList" :key="index" >
        <img :src="item.pic" alt="">
        <p>{{item.name}}</p>
      </div>
    </div>
    <div @click="handleClick" class="btn"></div>
  </div>
</template>

css

js 复制代码
<style lang="less" scoped>
.graph-page {
  width: 540px;
  height: 540px;
  margin: 100px auto;
  position: relative;
}
.plate-wrapper {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 10px solid #98d3fc;
  overflow: hidden;
}
.item-plate {
  position: absolute;
  left: 0;
  right: 0;
  top: -10px;
  margin: auto;
}
.item-plate img {
  width: 30%;
  height: 20%;
  margin: 40px auto 10px;
  display: block;
}
.item-plate p {
  color: #fff;
  font-size: 12px;
  text-align: center;
  line-height: 20px;
}
.btn {
  width: 160px;
  height: 160px;
  background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/btn_lottery.png') no-repeat center / 100% 100%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  cursor: pointer;
}
.btn::before {
  content: "";
  width: 41px;
  height: 39px;
  background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/icon_point.png') no-repeat center / 100% 100%;
  position: absolute;
  left: 0;
  right: 0;
  top: -33px;
  margin: auto;
}
</style>

js

其中背景色采用间隔配置,扇形背景采用锥形渐变函数conic-gradient可实现。

每个转项的宽度和高度可参照以下图片,所有奖品的div都定位在圆心以上,根据圆心转动,所以旋转点为底部中心,即:transform-origin: 50% 100%;

可采用监听transitionend事件判断动画是否结束,可自定义中奖提示。

js 复制代码
<script>
export default {
  data() {
    return {
      plateList: [],
      isRunning: false, //判断是否正在转动
      rotateAngle: 0, //转盘每项角度
      baseRunAngle: 360 * 5, //总共转动角度,至少5圈
      totalRunAngle: 0, //要旋转的总角度
      activeIndex: 0, //中奖index
      wrapDom: null //转盘dom
    }
  },
  computed: {
    bgColor(){ //转盘的每项背景
      let len = this.plateList.length
      let color = ['#5352b3', '#363589']
      let colorVal = ''
      this.plateList && this.plateList.forEach((item, index)=>{
        colorVal += `${color[index % 2]} ${(360/len)*index}deg ${(360/len)*(index+1)}deg,`
      })
      return `background: conic-gradient(${colorVal.slice(0, -1)})`
    },
    plateCss(){ //转盘的每项样式
      if(this.plateList && this.plateList.length){
        return (i) => {
          return `
            width: ${Math.floor(2 * 270 * Math.sin(this.rotateAngle / 2 * Math.PI / 180))}px;
            height: 270px;
            transform: rotate(${this.rotateAngle * i + this.rotateAngle / 2}deg);
            transform-origin: 50% 100%;
          `
        }
      }
      return ()=>{''}
    },
  },
  created(){
    this.plateList= [
      { name: '手机', pic: 'https://bkimg.cdn.bcebos.com/pic/3801213fb80e7bec54e7d237ad7eae389b504ec23d9e' },
      { name: '手表', pic: 'https://img1.baidu.com/it/u=2631716577,1296460670&fm=253&fmt=auto&app=120&f=JPEG' },
      { name: '苹果', pic: 'https://img2.baidu.com/it/u=2611478896,137965957&fm=253&fmt=auto&app=138&f=JPEG' },
      { name: '棒棒糖', pic: 'https://img2.baidu.com/it/u=576980037,1655121105&fm=253&fmt=auto&app=138&f=PNG' },
      { name: '娃娃', pic: 'https://img2.baidu.com/it/u=4075390137,3967712457&fm=253&fmt=auto&app=138&f=PNG' },
      { name: '木马', pic: 'https://img1.baidu.com/it/u=2434318933,2727681086&fm=253&fmt=auto&app=120&f=JPEG' },
      { name: '德芙', pic: 'https://img0.baidu.com/it/u=1378564582,2397555841&fm=253&fmt=auto&app=120&f=JPEG' },
      { name: '玫瑰', pic: 'https://img1.baidu.com/it/u=1125656938,422247900&fm=253&fmt=auto&app=120&f=JPEG' }
    ]
    this.rotateAngle = 360 / this.plateList.length
    this.totalRunAngle = this.baseRunAngle + 360 - this.activeIndex * this.rotateAngle - this.rotateAngle / 2 
  },
  mounted(){
    this.$nextTick(()=>{
      this.wrapDom = document.getElementsByClassName('plate-wrapper')[0]
    })
  },
  beforeDestroy(){
    this.wrapDom.removeEventListener('transitionend', this.stopRun)
  },
  methods:{
    handleClick(){
      if(this.isRunning) return 
      this.isRunning = true
      const ind = Math.floor(Math.random() * this.plateList.length)//通过随机数返回奖品编号
      this.activeIndex = ind
      this.startRun()
    },
    startRun(){
      // 设置动画
      this.wrapDom.setAttribute('style', `
        ${this.bgColor};
        transform: rotate(${this.totalRunAngle}deg);
        transition: all 4s ease;
      `)
      this.wrapDom.addEventListener('transitionend', this.stopRun) // 监听transition动画停止事件
    },
    stopRun(){
      this.isRunning = false
      this.wrapDom.setAttribute('style', `
        ${this.bgColor};
        transform: rotate(${this.totalRunAngle - this.baseRunAngle}deg);
      `)
    }
  }
}
</script>

参考来源:juejin.cn/post/718031...

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax