vue 中实现大转盘抽奖

 

想要开发一个,可进行配置奖品的大转盘抽奖活动:如下图:

要求: 转盘底图可配置,相对应的奖品也能够配置

 

    

 

 

 

开发思路:

  1. 可以把转盘开发成一个组件,所有参数皆是可配置的,做成组件具有公用型
  2. 通过 transform的rotate旋转 以及 transition过渡来实现动画
  3. 确定旋转实现的原理,不想能像表盘那样指针转,应该是指针不动,表盘旋转,用户体验性更好 

 

具体实现步骤:

 

  1.dom加载完成后,在mounted钩子中写一个transition平移动画

  

   //渲染完了
    mounted() {
      this.oTurntable = document.querySelector('#turnUl');
      // 过度中属性用时5s
      this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease';
    },

 

  2.先根据奖品列表数量来计算每个奖品对应的角度,指针一般是定位到该中奖奖品的中心位置,这个要考虑到

autoRotate(arr) {
      if (arr.length) {
          let len = arr.length;
          let base = 360 / len;
          arr.forEach((item, index) => {
            // 指的是某个奖品区域的中间 : base/2
            item.angle = 360 - (base / 2 + index * base);
          });
      }
      return arr;
},

 

 

  3.点击按钮时请求接口,拿到中奖奖品进行旋转到之前计算好的该奖品的角度,可以写在定时器当中,完成后即清除定时器

      // 点击开始,请求接口抽奖
      startPlay(){
        const a = {
          prize: "50元和包券",
          id: 4
        }
        this.startBtn(a)
      },
      // 开始转动,通过奖项级别进行匹配:id 
      startBtn(val) {
        const self = this
        self.activeObj.prizeData.forEach((i,d)=>{
          if(i.id == val.id){
            self.pIndex = d
          }
        })
        // 拿到相应的角度调旋转接口
        self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => {
          self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize);
        });
      },

      //开始旋转 angle角度  complete回调成功函数
      startrotate(angle, complete) {
        // 相应的角度 + 满圈 只是在原角度多转了几圈 360 * 6
        let rotate = 2160 * (this.rotNum + 1) + angle;
        this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)';
        clearTimeout(this.timer);
        // 设置5秒后停止旋转,处理接口返回的数据
        this.timer = setTimeout(() => {
          complete();
          this.rotNum++;
        }, this.time);
      },
      //得奖后的处理
      fulfillHandle(prizeName) {
        this.$emit('result',prizeName)
      },

 

  4.抽奖旋转结束后再去处理后续操作,写在startrotate 这个函数中,通过吧结束处理的函数当做参数进行回调

 

下面是完整代码:

html:

<template>
  <div id="turnBox">
    <ul id="turnUl" :style="{ backgroundImage : 'url(' + activeObj.turntableBgc + ')'}">
      <li
        v-for="(item,index) in activeObj.prizeData"
        :key="index"
        :style="{webkitTransform: 'rotate(' + -item.angle + 'deg)'}"
      >
      </li>
    </ul>
    <img :src="activeObj.turntablebtn" alt=""  @click="startPlay" class="turnBtn">
  </div>
</template>

 

js:

<script>
  export default {
    props: {
      activeObj: {
        type: Object,
        default: null
      },
    },
    data(){
      return {
        pIndex: 0, // 中奖物品的下标
        rotNum:  0, // 旋转圈数基数
        time: 5000, // 旋转时间
        timer: null, // 定时器
        oTurntable: '', // 旋转圆盘背景图
        type: 0, // 0 图片 1 汉字
      }
    },   
    created() {
      this.activeObj.prizeData = this.autoRotate(this.activeObj.prizeData)
      console.log(this.activeObj.prizeData);
    },
    //渲染完了
    mounted() {
      this.oTurntable = document.querySelector('#turnUl');
      // 过度中属性用时5s
      this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease';
    },
    methods:{
      //自动生成角度添加到数组上
      autoRotate(arr) {
        if (arr.length) {
          let len = arr.length;
          let base = 360 / len;
          arr.forEach((item, index) => {
            // 指的是某个奖品区域的中间 : base/2
            item.angle = 360 - (base / 2 + index * base);
          });
        }
        return arr;
      },
      // 点击开始,请求接口抽奖
      async startPlay(){
        const a = {
          prize: "50元和包券",
          id: 4
        }
        this.startBtn(a)
      },
      // 开始转动,通过奖项级别进行匹配:id 
      async startBtn(val) {
        const self = this
        self.activeObj.prizeData.forEach((i,d)=>{
          if(i.id == val.id){
            self.pIndex = d
          }
        })
        // 拿到相应的角度调旋转接口
        self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => {
          self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize);
        });
      },

      //开始旋转 angle角度  complete回调成功函数
      startrotate(angle, complete) {
        // 相应的角度 + 满圈 只是在原角度多转了几圈 360 * 6
        let rotate = 2160 * (this.rotNum + 1) + angle;
        this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)';
        clearTimeout(this.timer);
        // 设置5秒后停止旋转,处理接口返回的数据
        this.timer = setTimeout(() => {
          complete();
          this.rotNum++;
        }, this.time);
      },
      //得奖后的处理
      fulfillHandle(prizeName) {
        this.$emit('result',prizeName)
      },
      
      //自动换行
      autoWrap(str) {
        if (str.length > 5 && str.length <= 10) {
          str = str.substring(0, 5) + '<br/>' + str.substring(5, str.length);
        } else if (str.length > 10) {
          str = str.substring(0, 5) + '<br/>' + str.substring(5, 9) + '...';
        }
        return str;
      }
    }
  }
</script>

 

css:

<style lang="less" scoped>
  #turnBox {
    width: 545px;
    height: 544px;
    position: relative;
    overflow: hidden;
    margin: 0px auto;
    margin-top: 30px;
    background-position: center center;
    .turnBtn {
      position: absolute;
      width: 1.3rem;
      left: 50%;
      top: 50%;
      transform: translateX(-50%) translateY(-59%);
      overflow: hidden;
      background-repeat: no-repeat;
      background-size: 100% auto;
      z-index: 3;
    }
    ul {
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 1;
      background-repeat: no-repeat;
      background-size: 100% auto;
      li {
        position: absolute;
        box-sizing: border-box;
        // padding-top: 0.5rem;
        color: #7e250d;
        font-size: 0.3rem;
        top: 0pc;
        left: 0px;
        width: 100%;
        height: 100%;
        line-height: 20px;
        transform-origin: 50% 50%;
        img {
          position: absolute;
          top: 0.3rem;
          left: 50%;
          transform: translateX(-50%);
          width: 20%;
        }
      }
    }
  }

</style>

 

posted @ 2020-04-30 14:59  银翘解毒片  阅读(13722)  评论(3编辑  收藏  举报