首页 > 其他分享 >vue大转盘旋转效果-停在随机定位的奖品处

vue大转盘旋转效果-停在随机定位的奖品处

时间:2023-09-15 18:32:46浏览次数:47  
标签:奖品 vue prize img transform 大转盘 nth rotate child

代码有点乱,给予vue写的,奖品可以自定义数量

抽奖也是随机生成了奖品的下标,然后停在该下标的位置

里面有个大转盘的背景图,自己随便找个圆形图片放上去就行了

<!-- 这个案例大概实现了停止在初始位置,误差在±10度左右 增加了奖品分布-->
<template>
  <div class="hello">
    <div class="container" :style='{"transform":"rotate("+rotate+"deg)"}'>
      <div class="turntable">
        <div class="prize" v-for="(item,index) in zp_gift_list" :key="index" :style='{"transform":"rotate("+(zp_gift_step*index-zp_gift_rotate_ni)+"deg)"}'>
<!--                <div class="prize-child" :style='{"transform": "rotate("+(zp_gift_step*index)+"deg) skewY(-30deg)"}'>-->
          <div class="prize-child" :style='{"transform": "rotate(45deg) skewY(0deg)"}'>
            <div>
              <img :src="item.img" alt="">
            </div>
            <div>{{item.name}}</div>
          </div>
        </div>
      </div>
      <div class="draw-btn" @click="startRotate"></div>
    </div>
    <!-- <img src="@/assets/zhuanpan.png" ref="logo" :style='{"transform":"rotate("+rotate+"deg)"}' class="shunhua"> -->
    <button @click="startRotate">开始</button>
    <button @click="stopRotate">停止</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      //元素当前角度
      rotate:0,
      //定时器对象
      interverObj:null,
      //旋转步进角度
      rotateStep:1,
      //最大步进角度
      rotateStepMax:10,
      //每多少毫秒累加一次步进角度
      rotateAddTime:100,
      //每多少毫秒运行一次
      rotateRunTimeOut:10,
      //当前运行毫秒数
      nowRunTime:0,
      //旋转状态0停止中 1旋转中 2停止中
      rotateState:0,
      //停止旋转步进角度
      rotateStepStop:1,
      //---------------------------------------转盘奖品相关变量
      //奖品列表
      zp_gift_list:[
        {name:'aaa',img:''},
        {name:'bbb',img:''},
        {name:'ccc',img:''},
        {name:'ddd',img:''},
        {name:'eee',img:''},
        {name:'fff',img:''},
        {name:'ggg',img:''},
        {name:'hhh',img:''},
        {name:'iii',img:''},
        {name:'jjj',img:''},
      ],
      //礼物倾斜角度步进值
      zp_gift_step:0,
      //奖品逆角度
      zp_gift_rotate_ni:44,
      //转盘刹停范围
      zp_stop_range:[]
    }
  },
  mounted(){
    // this.startRotate()
    this.getGiftRotate()
  },
  methods:{
    //计算出每个奖品占用的角度
    getGiftRotate(){
      this.zp_gift_step = 360/this.zp_gift_list.length
    },
    //重置相关参数
    resetData(){
      //元素角度
      // this.rotate = 0
      //定时器对象
      clearInterval(this.interverObj)
      this.interverObj = null
      //步进角度
      this.rotateStep = 1
      //当前运行毫秒数
      this.nowRunTime = 0
      //旋转状态0停止中 1旋转中 2停止中
      this.rotateState = 0
    },
    //启动旋转
    startRotate(){
      let that = this
      if(that.rotateState == 0){
        that.rotateState = 1
        that.interverObj = setInterval(function(){that.rotateLogo()},that.rotateRunTimeOut)
      }
      
    },
    //停止旋转
    stopRotate(){
      if(this.rotateState == 1){
        this.getGiftIndexRotate()
        this.rotateState = 2
      }
      //计算距离回正方向差多少度
      // let cha = 720 - this.rotate % 360
      //计算出每次执行需要降速多少度,假设2秒刹车完毕:差多少度/(2000/每次变速时间)
      // this.rotateStepStop = cha/(50000/this.rotateAddTime)
    },
    //控制旋转步进角度
    handleRotate(){      
      if(this.rotateState == 1){//如果当前为旋转中
        //步进角度小于最大步进角度
        if(this.rotateStep < this.rotateStepMax){
          if(this.nowRunTime % this.rotateAddTime == 0){
            //继续累加步进角度
            this.rotateStep += this.rotateStep
          }          
        }
      }else if(this.rotateState == 2){//如果当前为停止中
        if(this.nowRunTime % this.rotateAddTime == 0){
          //减少步进角度
          if((this.rotateStep - this.rotateStepStop)>2){//如果减少之后,步进角度大于0,就继续减少
            this.rotateStep -= this.rotateStepStop
          }else{//否则就是要停止了
            let cha = this.rotate % 360
            //如果在以下角度范围内就停止转动,此判断不涉及到停止在指定奖品角度内
            // if( (cha>=0 && cha<=5) || (cha>=355 && cha<=359) ){
            if( (cha>=this.zp_stop_range[0][0] && cha<=this.zp_stop_range[0][1]) || (cha>=this.zp_stop_range[1][0] && cha<=this.zp_stop_range[1][1]) ){
            // if( (cha>=306 && cha<=324) || (cha>=324 && cha<=342) ){
              this.rotateStep = 0
              this.resetData()
            }
            //如果在以下角度范围就停转,此角度是指定奖品所在的角度
          }          
        }
      }else{//静止状态

      }      
    },
    //随机得出奖品的角度
    getGiftIndexRotate(){
      let res = []
      //随机奖品下标
      let i = Math.round(Math.random()*(this.zp_gift_list.length-1))
      // let cha = this.zp_gift_step * (giftIndex + 1) / 2
      //计算开始范围和结束范围
      let j = this.zp_gift_step/2

      if(i == 0){
        res.push([(360-(2*i+1)*j+j),359])
        res.push([0,(360-(2*i-1)*j)])
      }else{
        res.push([(360-(2*i+1)*j),(360-(2*i+1)*j+j)])
        res.push([(360-(2*i+1)*j+j),(360-(2*i-1)*j)])
      }

      this.zp_stop_range = res
      console.log("停止下标:"+i,res)
    },
    //执行旋转
    rotateLogo(){
      //累加运行毫秒数
      this.nowRunTime += this.rotateRunTimeOut
      //累加旋转角度
      this.rotate += this.rotateStep
      //调用控制旋转步进角度函数
      this.handleRotate()
    }    
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  .shunhua{
    transition: 0.1s;
  }
  .container {
    width: 300px;
    height: 300px;
    /*background-color: red;*/
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    background-image: url("../assets/zhuanpan.png");
    background-position: center;
    background-size: 100%;
    color: white;

    /*animation: mymove 8s;*/
    /*-webkit-animation: mymove 8s; !* Safari 与 Chrome *!*/
    /*animation-iteration-count: infinite;*/
    /*animation-timing-function: ease;*/
  }

  .turntable {
    width: 280px;
    height: 280px;
    border-radius: 50%;
    position: absolute;
    overflow: hidden;
  }

  /*扇形区*/
  .prize-container {
    width: 280px;
    height: 280px;
    background-color: bisque;
    position: absolute;
    left: 50%;
    top: -50%;
    /*600-280/2,将prize正方形左下角点对准圆心*/
    border: 1px solid red;
    /*以正方形左下角为中心旋转,0% 100%即左下角的坐标*/
    transform-origin: 0% 100%;
  }

  .prize-container:nth-child(1) {
    transform: rotate(0deg) skewY(-30deg);
  }

  .prize-container:nth-child(2) {
    transform: rotate(60deg) skewY(-30deg);
  }

  .prize-container:nth-child(3) {
    transform: rotate(120deg) skewY(-30deg);
  }

  .prize-container:nth-child(4) {
    transform: rotate(180deg) skewY(-30deg);
  }

  .prize-container:nth-child(5) {
    transform: rotate(240deg) skewY(-30deg);
  }

  .prize-container:nth-child(6) {
    transform: rotate(300deg) skewY(-30deg);
  }

  /* 奖品区 */
  .prize {
    width: 140px;
    height: 140px;
    position: absolute;
    left: 50%;
    top: 0;
    transform-origin: 0% 100%;
  }

  /* 奖品内容 */
  .prize-child {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transform: rotate(30deg) translateX(-15%) translateY(10%);
  }
  .prize-child div:nth-child(1){
    width: 30px;
    height: 30px;
    /*background-color: blue;*/
  }
  .prize-child img{
    width: 100%;
    height: 100%;
  }
  .prize-child div:nth-child(2){
    font-size: 12px;
  }

  .prize:nth-child(1) {
    transform: rotate(0deg);
  }

  .prize:nth-child(2) {
    transform: rotate(60deg);
  }

  .prize:nth-child(3) {
    transform: rotate(120deg);
  }

  .prize:nth-child(4) {
    transform: rotate(180deg);
  }

  .prize:nth-child(5) {
    transform: rotate(240deg);
  }

  .prize:nth-child(6) {
    transform: rotate(300deg);
  }

  .draw-btn {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    /*background-color: red;*/
    color: white;
    font-size: 30px;
    line-height: 80px;
    text-align: center;
    position: absolute;
    /* background-image: url("../assets/img/zhuanpan/zhen.png"); */
    background-position: center;
    background-size: 100%;
  }
</style>

标签:奖品,vue,prize,img,transform,大转盘,nth,rotate,child
From: https://blog.51cto.com/u_15668841/7485590

相关文章

  • vue3.3.x setup 新实验性特性 defineModel 定义多个属性
    由于有些业务组件需要定义多个响应式props,类似这种(比较懒,没上ts),在vue3.3.x以前,如果不用三方库,代码会变得很繁琐<scriptsetup> constprops=defineProps({ modelValue:{ type:Object, default:()=>({}) }, fields:{ type:Object, default:()=>(......
  • vue前后端分离项目中,对于空字符串转可空类型出错的解决办法
    环境:netcore 6.0+序列化采用自带的System.Text.Json工具使用vue做前后端分离时,我们提交的对象中,可能有些字段是为空字符串,但是对应接口要求是int?,decimal?datetime?等类型。那么在序列化时,就会报错。因为空字符串无法直接反序列化为null 所以我们需要自定义一个转换规......
  • 原生HTML单页面使用vue框架
     <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=devi......
  • antdesign vue通用表单生成页面
    效果图效果图由于涉及企业敏感信息,信息进行了打码,还请多多包涵。。。点击左侧菜单树,右侧加载不同table,并且绑定列名不同(说明:前两列企业名称和城市名称固定不变)技术思路左侧菜单为标识,控制表单页面的布局和模块显示,字段显示隐藏,可根据下面2附图加深理解,由于信息敏感问题,暂时不提供......
  • vue-day02
    模版语法html<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title><scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>&......
  • Vue Debug Reac 配置
    https://zhuanlan.zhihu.com/p/475999585 作为前端开发,基本每天都要调试Vue/React代码,不知道大家都是怎么调试的,但我猜大概有这么几种:不调试,直接看代码找问题console.log打印日志用ChromeDevtools的debugger来调试用VSCode的debugger来调试不同的调试方式效......
  • vue vue-devtools调试工具神器安装
    目录vuevue-devtools调试工具神器安装前言chrome商店直接安装手动安装第一步:找到vue-devtools的github项目,并将其clone到本地.vue-devtools第二步:安装项目所需要的npm包第三步:编译项目文件第四步:添加至chrome游览器vue-devtools如何使用文章转自vuevue-devtools调试工具神器安......
  • vue3videplayer播放m3u8视频流注意事项
    前言使用vue3开发项目时,碰上需要做一个视频流列表的页面,最开始是想获取所有列表数据后创建对应的video标签,这样默认获取第一帧作为封面,同时暂停视频减轻不断请求的压力。但开发后发现视频就算暂停后也会继续请求视频流,多个视频反而会导致页面卡顿。方案手动获取视频的第一......
  • Vue——模版语法、文本指令、事件指令、属性指令、style和class、条件渲染、列表渲染
    模版语法<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title><scriptsrc="./js/vue.js"></script></head><body><divid=&......
  • vue背景及快速使用
    前端介绍1.HTML(5)、CSS(3)、JavaScript(ES5、ES6、ES11):编写一个个的页面->给后端(PHP、Python、Go、Java)->后端嵌入模板语法->后端渲染完数据->返回数据给前端->在浏览器中查看2. Ajax的出现->后台发送异步请求,Render+Ajax混合3.单用Ajax(加载数据,DOM渲染页......