转盘抽奖的实现

如图效果展示:(因最近双十一,公司需求要给新老客服抽奖发福利,临时写的)

核心代码:

 async rotating() {
            var type = 0; // 默认为 0  转盘转动 1 箭头和转盘都转动(暂且遗留)
            var during_time = 5; // 默认为1s
            var result_index = this.index-1; // 最终要旋转到哪一块,对应prize_list的下标
            var result_angle = [190 ,139 ,88 ,37 ,-14,-65  ,-116]  //这里是指定位置
            var rand_circle = 6; // 附加多转几圈,2-3
            var rotate_angle = 0;
            this.count++
            if (type == 0) {
              // 转动盘子
              var rateround=rand_circle * 360 + result_angle[result_index]     //这里是(转盘算法) rateround是转动的距离  this.start_rtating是每次初始化转盘的位置 
              rotate_angle =this.start_rotating_degree + rateround
              -this.start_rotating_degree  %  360 ;
              this.start_rotating_degree = rotate_angle;
              this.rotate_angle = "rotate(" + rotate_angle + "deg)";
              this.lottery_ticket--;
              let that = this
              setTimeout(function() {
                that.game_over(); //提示框
              },during_time * 1000 + 1500)// 延时,保证转盘转完
      } 
    },

做这个的时候,因为不是很理解转盘算法,第一次点击转盘可以转向指定位置,而第二次后都是有点偏移。这里主要靠 %360来取余,不管你指定位置多少,最终都是要 减去初始位 % 360。

详细代码如下:

<template>
<!-- 新客户链接 -->
  <div class="container">
    <div class="draw-title">
      <div class="draw-name">{{title}}</div>
    </div>
    <div class="lucky-wheel">
      <div class="wheel-main">
        <div class="wheel-pointer-box">
          <div class="wheel-pointer" @click="rotate_handle()" :style="{transform:rotate_angle_pointer,transition:rotate_transition_pointer}"></div>
        </div>
        <div class="wheel-bg" :style="{transform:rotate_angle,transition:rotate_transition}">
          <div class="prize-list">
            <div class="prize-item" v-for="(item,index) in prize_list" :key="index">
              <div class="prize-pic">
                <!-- <img :src="item.prizeImg"> -->
              </div>
              <div class="prize-count">
                <span v-if="item.gradeNum!=7">{{item.gradeName}}</span>
              </div>
              <div class="prize-text">
                <span v-if="item.gradeNum!=7">{{item.prizeName}}</span>
                
              </div>
              <div class="prize-type">
                <span v-if="item.gradeNum==7">{{item.gradeName}}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="main">
      <div class="content">
        <div class="lottery_ticket"></div>
        <div class="scroll_bg">
          <ul class="scroll_content"  :style="{ top }">
            <li v-for="(item,index) in WinList" :key="index" >
              <el-row>
                <el-col :span="6">{{index+1}}.{{item.phone | iphone}}</el-col>
                <el-col :span="14">{{item.prizeGrade.prizeName}}</el-col>
                <el-col :span="4">{{item.timeAgo}}</el-col>
              </el-row>
            </li>
          </ul>
        </div>
        
      </div>
      <div class="lotter_foot">
        <span class="left" @click="getMyPrizeRecord">我的奖品 ></span>
        <span class="right" @click="todrawRule">活动规则 ></span>
      </div>
    </div>
    <!-- 输入手机号 -->
    <div class="toast" v-show="toast_phoneNum">
      <div class="toast-container">
        <!-- <img :src="toast_pictrue" class="toast-picture"> -->
        <div class="close" @click="close_phoneNum()"></div>
        <div class="toast-title">
          <span style="margin-right:10px;">手机号:</span>
          <el-input size="small" style="width:60%;height:0.75rem;" v-model="phoneNum"></el-input>
        </div>
        <div class="toast-btn">
          <div class="toast-cancel"  @click="runDraw">确 认</div>
        </div>
      </div>
    </div>
    <div class="toast-mask" v-show="toast_phoneNum"></div>

    <!-- 输入手机号 -->
    <div class="toast" v-show="toast_myphonecontrol">
      <div class="toast-container">
        <!-- <img :src="toast_pictrue" class="toast-picture"> -->
        <div class="close" @click="close_phoneNum()"></div>
        <div class="toast-title">
          <span style="margin-right:10px;">手机号:</span>
          <el-input size="small" style="width:60%;height:0.75rem;" v-model="phoneNum"></el-input>
        </div>
        <div class="toast-btn">
          <div class="toast-cancel"  @click="runphone">确 认</div>
        </div>
      </div>
    </div>
    <div class="toast-mask" v-show="toast_myphonecontrol"></div>


    <!-- 中奖提示 -->
    <div class="toast" v-show="toast_control">
      <div class="toast-container">
        <!-- <img :src="toast_pictrue" class="toast-picture"> -->
        <div class="close" @click="close_toast()"></div>
        <div class="toast-title">
          {{toast_title}}
        </div>
        <div class="toast-btn">
          <div class="toast-cancel"  @click="close_toast">确 认</div>
        </div>
      </div>
    </div>
    <div class="toast-mask" v-show="toast_control"></div>
    <!-- 我的奖品 -->
    <div class="toast" v-show="toast_mycontrol">
      <div class="toast-container">
        <!-- <img :src="toast_pictrue" class="toast-picture"> -->
        <div class="close" @click="close_mytoast()"></div>
        <div class="toast-title">
          <div>抽中奖品列表</div>
          <li v-for="(item,index) in mycontList" :key="index">
            {{item.entities.gradeName}}——{{item.luckDrawTime | datetime('date')}}
          </li>
        </div>
        <div class="toast-btn">
          <div class="toast-cancel"  @click="close_mytoast">确 认</div>
        </div>
      </div>
    </div>
    <div class="toast-mask" v-show="toast_mycontrol"></div>
  </div>
</template>
<script>
import {getPrizeActivityById,getPrizeList,startRaffle,checkLuckyDraw,getMyPrizeRecord,getPrizeRecordTopTenList  } from '../../api/getData';
export default {
  data(){
    return{
      index:0,
      angle:0,
      toast_title:'',
      start_rotating_degree: 0, //初始旋转角度
      rotate_angle: 0, //将要旋转的角度
      start_rotating_degree_pointer: 0, //指针初始旋转角度(360/分页)
      rotate_angle_pointer: 0, //指针将要旋转的度数
      rotate_transition: "transform 6s ease-in-out", //初始化选中的过度属性控制
      rotate_transition_pointer: "transform 12s ease-in-out", //初始化指针过度属性控制
      lottery_ticket:1,//抽奖次数
      prize_list: [], //奖品列表
      toast_control:false,
      toast_mycontrol:false,
      click_flag:true, //是否可以旋转抽奖
      toast_phoneNum:false,
      toast_myphonecontrol:false,
      phoneNum:'',
      WinList:[],//中奖名单
      activeIndex: 0,
      activityId:null, //用户id
      mycontList:[],
      title:''
    }
  },
  watch:{
    $route(){
      console.log(this.$route.query.id)
      console.log(this.$route.meta.title)
    }
  },

  methods:{
    async getPrizeList(){
        const result = await getPrizeList({activityId:this.activityId})
        if(result.code == 200){
          this.prize_list = result.data
        }else{
          this.$toast({message:result.message ,position:'top'});
        }
    },
    
    rotate_handle(){
      this.phoneNum = ''
      if(!this.phoneNum){
        this.toast_phoneNum = true
      }
    },
    async runDraw(){
      if(this.phoneNum.length!=0){
        var reg=/^1[3456789]\d{9}$/;
        if(!reg.test(this.phoneNum)) return this.$toast({message:'请输入有效的手机号码' ,position:'top'});

        const result = await checkLuckyDraw({phoneNumber:this.phoneNum,activityId:this.activityId})
          if(result.code == 200){
          //需要判断
            const result = await startRaffle({phoneNumber:this.phoneNum,activityId:this.activityId})
            if(result.code == 200){
              this.index = result.data.gradeNum;
              this.rotating()
            }else{
              this.$toast({message:result.message ,position:'top'});
            }
            this.toast_phoneNum = false
          }else{
            this.$toast({message:result.data ,position:'top'});
          }
      }else{
        this.$toast({message:'手机号不能为空!' ,position:'top'});
      }
    },
    async runphone(){
      if(this.phoneNum.length!=0){
       
        var reg=/^1[3456789]\d{9}$/;
        if(!reg.test(this.phoneNum)) return this.$toast({message:'请输入有效的手机号码' ,position:'top'});
        const result = await checkLuckyDraw({phoneNumber:this.phoneNum,activityId:this.activityId})
          if(result.code == 500){
          //需要判断
            this.toast_myphonecontrol = false
            this.toast_mycontrol = true
            this.getMyPrizeRecord()
          }else{
            this.$toast({message:result.data ,position:'top'});
          }
         
      }else{
        this.$toast({message:'手机号不能为空!' ,position:'top'});
      }
    },
    async rotating() {
            var type = 0; // 默认为 0  转盘转动 1 箭头和转盘都转动(暂且遗留)
            var during_time = 5; // 默认为1s
            var result_index = this.index-1; // 最终要旋转到哪一块,对应prize_list的下标
            var result_angle = [190 ,139 ,88 ,37 ,-14,-65  ,-116]
            var rand_circle = 6; // 附加多转几圈,2-3
            var rotate_angle = 0;
            this.count++
            if (type == 0) {
              // 转动盘子
              var rateround=rand_circle * 360 + result_angle[result_index]
              rotate_angle =this.start_rotating_degree + rateround
              -this.start_rotating_degree  %  360 ;
              this.start_rotating_degree = rotate_angle;
              this.rotate_angle = "rotate(" + rotate_angle + "deg)";
              this.lottery_ticket--;
              let that = this
              setTimeout(function() {
                that.game_over(); //提示框
              },during_time * 1000 + 1500)// 延时,保证转盘转完
      } 
        
    },
    game_over() {
      if(this.prize_list[this.index-1].prizeName=='') return
      this.toast_control = true;
      if(this.prize_list[this.index-1].gradeNum ==7){
        return this.toast_title = "抽中结果为:"+this.prize_list[this.index-1].gradeName
      }else{
        return this.toast_title = "抽中结果为:"+this.prize_list[this.index-1].prizeName+this.prize_list[this.index-1].gradeName
      }
        
    },
    async getMyPrizeRecord(){
      if(this.phoneNum){
          const result = await getMyPrizeRecord({phoneNumber:this.phoneNum,activityId:this.activityId})
          if(result.code == 200){
            this.toast_mycontrol = true;
            this.mycontList = result.data
          }else{
            this.$toast({message:result.message ,position:'top'});
          }
      }else{
        this.toast_myphonecontrol = true
      }
    },
    close_mytoast(){
      this.toast_mycontrol = false
    },
    //关闭弹窗
    close_toast() {
      this.toast_control = false;
      this.getPrizeRecordTopTenList()
    },
    //关闭手机号录入
    close_phoneNum(){
      this.toast_phoneNum = false;
      this.toast_myphonecontrol= false
    },
    todrawRule(){
      this.$router.push('/newdrawRule?id='+this.$utils.getUrlKey('id'))
    },
    async getPrizeRecordTopTenList(){
        const result = await getPrizeRecordTopTenList({activityId:this.activityId})
        if(result.code == 200){
          this.WinList = result.data
        }else{
          this.$toast({message:result.message ,position:'top'});
        }
     
    },
    async getPrizeActivityById(){
        const result = await getPrizeActivityById({id:this.$utils.getUrlKey('id')})
        if(result.code == 200){
          this.activityId = result.data.id
          this.title = result.data.name
          document.title = this.title
          this.getPrizeList()  
          this.getPrizeRecordTopTenList()
        }else{
          this.$toast({message:result.message ,position:'top'});
        }
    }
  },
  mounted(){
    let _this = this; 
    let timer = setInterval(function(){
      if(_this.WinList.length){
        let b = _this.WinList.shift()
        _this.WinList.push(b)
      }
    }, 2000);
    this.getPrizeActivityById()
    
  },
  computed:{
    top() {
      return  -this.activeIndex * 1.35 + 'rem'
    }
  }
  
}
</script>
<style lang="less"> 
.container {
  width: 100%;
  background: url("../../assets/img/draw/bgdraw.jpg") no-repeat;
  background-size: 100% ;
  .draw-title{
    position: absolute;
    top: 1.225rem;
    left: 50%;
    transform: translateX(-50%);
    background-size: 100% ;
    width: 90%;
    height: 3.5625rem;
    .draw-name{
      margin: auto;
      color: rgb(110,20,54);
      font-weight: 600;
      background: rgb(255,228,1);
      border: .2rem solid rgb(254, 118, 0);
      border-radius: .2rem;
      padding: 0.4rem ;
      text-align: center;
    }
  }
 
  .lucky-wheel{
    width: 100%;
    height: 42.5625rem;
    padding-top: 23.5625rem;
    .wheel-main {
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      .wheel-pointer-box {
        position: absolute;
        top: 50%;
        left: 49.2%;
        z-index: 100;
        transform: translate(-50%, -50%);
        width: 18.3125rem;
        height: 18.3125rem;
        background: url("../../assets/img/draw/drawtab.png") no-repeat center top;
        background-size: 100%;
        .wheel-pointer {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          width: 15.3125rem;
          height: 15.3125rem;
          background: url("../../assets/img/draw/drawbtn.png") no-repeat;
          background-size: 100% 100%;
          transform-origin: center 60%;
        }
      }
      .wheel-bg {
        width: 18.4375rem;
        height: 18.4375rem;
        background: url("../../assets/img/draw/turntable.png") no-repeat center top;
        background-size: 100%;
        transform: rotate(12deg);
        font-weight: 500;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-content: center;
        transition: transform 3s ease;
        div {
          text-align: center;
        }
        .prize-list{
          width: 100%;
          height: 100%;
          position: relative;
          .prize-item {
            font-size: 0.45rem;
            position: absolute;
            top: 10%;
            left: 39%;
           
            width: 3.9rem;
            height: 14.5rem;
            padding-top: 0.5rem;
            margin: auto;
            z-index: 2;
            line-height: 0.85rem;
            .prize-pic img {
              width: 4.0625rem;
              height: 2.5rem;
              margin-top: 1.5625rem;

            }
            .prize-count{
              font-size: 0.55rem;
            }
            .prize-text {
              font-size: 0.55rem;
            }
            .prize-type {
              font-size: 0.55rem;
              padding-top: 1rem;
            }
          }
          .prize-item:first-child {
            transform: rotate(-194deg);
          }
          .prize-item:nth-child(2) {
            transform: rotate(-140deg);
          }
          .prize-item:nth-child(3) {
            transform: rotate(-88deg);
          }
          .prize-item:nth-child(4) {
            transform: rotate(-38deg);
          }
          .prize-item:nth-child(5) {
            transform: rotate(13deg);
          }
          .prize-item:nth-child(6) {
            transform: rotate(63deg);
          }
          .prize-item:nth-child(7) {
            transform: rotate(114deg);
          }
        }
        
      }
    }
  }
  .main{
    position: relative;
    width: 100%;
    padding-bottom: 1.6875rem;
    .content {
      position: relative;
      top: 0.175rem;
      left: 0;
      background: url("../../assets/img/draw/winner.png") no-repeat center top;
      background-size: 100%;
      width: 100%;
      height: 12.68rem;
      margin: auto;
      font-size: 1.125rem;
      color: #ffeb39;
      text-align: center;
      .lottery_ticket{
        height: 4rem;
      }
      .scroll_bg{
        height: 5.5rem;
        margin-top: 1.43rem;
        overflow: hidden;
        position: relative;
        .scroll_content{
          position: relative;
          transition: top 0.5s;
          -webkit-transition: top 0.5s;
        }
        ul{
          margin:0rem 2rem 1rem;
          font-size: .55rem;
          line-height: 1.35rem;
          // height: 30.14rem;
          // overflow: scroll;
        }
        li{
          line-height:1.35rem;
        }
      }
      
    }
    .lotter_foot{
      color: #fff;
      z-index: 999;
      width: 90%;
      margin:1.8rem auto;
      font-size: 0.75rem;
    }
   
  }
  .toast {
    position: fixed;
    top: 50%;
    left: 50%;
    z-index: 20000;
    transform: translate(-50%, -50%);
    width: 15.4375rem;
    background: #fff;
    border-radius: 0.3125rem;
    padding: 0.3125rem;
    background-color: rgb(252, 244, 224);
    .toast-container {
      position: relative;
      width: 100%;
      height: 100%;
      border: 1px dotted #fccc6e;
      .close {
        position: absolute;
        top: -0.9375rem;
        right: -0.9375rem;
        width: 2rem;
        height: 2rem;
        background: url("../../assets/img/draw/close_store.png") no-repeat center top;
        background-size: 100%;
      }
      .toast-title {
        padding: 2.8125rem 0;
        font-size: 0.75rem;
        color: #fc7939;
        text-align: center;
      }
      .toast-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        margin-bottom: 0.9375rem;
        div {
          background-image: -moz-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%, rgb(252, 124, 88) 99%);
          background-image: -ms-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%,rgb(252, 124, 88) 99%);
          background-image: -webkit-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%,rgb(252, 124, 88) 99%);
          box-shadow: 0px 4px 0px 0px rgba(174, 34, 5, 0.7);
          width: 4.6875rem;
          height: 1.875rem;
          border-radius: 1.875rem;
          text-align: center;
          line-height: 1.875rem;
          color: #fff;
        }
      }
    }
  }
  .toast-mask {
    position: fixed;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 1000;
    width: 100%;
    height: 100%;
  }
  .van-toast van-toast--top van-toast--text{
    z-index: 9999;
  }
}

</style>

猜你喜欢

转载自www.cnblogs.com/Arthur123/p/11784550.html