H5转盘

参考juejin.cn/post/696131…

想尽快的复制结果,看标题2

1.首先要理解transition与transform, transition需要事件触发才生效

1transform 表示的是过渡的效果,从a状态到b状态的一个转换,所以必须要有事件去触发,没法在网页加载时自动发生
2transform是 转换,指的是改变所在元素的外观,它有很多种手段(转换函数)来改变外观,例如 位移、缩放、旋转 等,而其中的位移的函数名就叫translate,所以说,translate是transform的一部分。transform是没有动画效果,你改变了它的值,元素立马改变

当我想要看到旋转360度这个效果时,发现浏览器,直接显示结果

 <div id="test"></div>
 #test {
  width: 100px;
  height: 100px;
  background-color: red;
  transition: transform 5s ease-in-out 0s;
  transform:  rotate(360deg);
}
复制代码

显示效果是:

image.png

所以我们应该改成:

  <div id="test"></div>
  <div onclick="test()">点击</div>
  <style>
    #test {
      width: 100px;
      height: 100px;
      background-color: red;
    }
    .test {
      transition: transform 5s ease-in-out 0s;
      transform:  rotate(360deg);
    }
  </style>
</head>
<body>
  <script>
    function test() {
      document.getElementById('test').className = 'test'
    }
  </script>
复制代码

抽奖5.gif

2.实现静态转盘的抽奖

抽奖4.gif

 data() {
    return {
      rotateAngle: 0, // 旋转角度
      config: {
        duration: 3000, // 总旋转时间 ms级
        circle: 7, // 旋转圈数
        mode: 'ease-in-out', // 由快到慢 惯性效果都省了
      },
      drawIndex: 0, // 中奖索引 转盘图片排序 指针右手开始 0-... 0-5
      juneInfoStatusObj: {
        residueCount: 0, // 剩余抽奖次数
      },
      run: false, // 是否在转动
      rewardMaskVisible: false, // 中奖的弹框
      rewardList: [],
    }
  },
  async mounted() {
    this.$loading.show()
    try {
      await this.getActivity21StJuneInfo()
    } finally {
      this.$loading.hide()
    } 
  },
   methods: {
    // 基础信息
    async getActivity21StJuneInfo() {
      const data = await xxxxxxx接口(this.token)
      const { residueCount = 0 } = data
      this.juneInfoStatusObj = { residueCount } // 先拿到可抽奖的次数,代码有删减,如果你们只需要抽奖一次可以去掉
    },
    // 点击转盘后拿到指定的项
    async getActivity21StJuneLottery() {
      const { reward } = await 该中什么奖的接口xxxx(this.token)
      this.rewardList = [ reward ] // 后端直接返回用户中了什么奖
      this.drawIndex = reward.id // 后端直接返回用户该中哪个奖
    },
    // 开始转动
    async startPlay() {
      if (!this.checkToken()) return //这里我们做了一个判断是否登录的操作,不需要的可以去掉
      if (+this.rotateAngle > 0) {
        this.$toast('正在抽奖中请不要重复点击')
        return 
      }
      if (+this.juneInfoStatusObj.residueCount === 0) {
        this.$toast('操作已达到上限')
        return
      }
      await this.getActivity21StJuneLottery()
      this.run = true
      this.rotateAngle = this.config.circle * 360 - (30 + this.drawIndex * 60)
    },
  },
复制代码

this.rotateAngle = this.config.circle * 360 - (30 + this.drawIndex * 60)最重要的是理解这个,首先你要保证,抽奖的指针是正对着中间线的,不偏向于任何一个模块,那么如果是6个区域,对应的就是每个区域360/6=60度,从顺时针看的话,第一个区域对应的是index = 0, 第二个区域对应的是index = 1 …..第六个区域就是index = 5,后端如果返回index=4,那也就是指向第五个区域. config对象里面的配置,转多少圈可以和产品商量, 圈数*360就是转多少圈

如果是转盘顺时钟旋转,指针不动,表示index=5, index=4,index…index=0 按照顺序通过指针,如果后端返回的index= 0, 也就是在旋转到接近360度的中间,360-30, this.config.circle * 360 – (30 + this.drawIndex * 60),一定要记住,指针不动,转盘动,转盘的区域旋转路径是怎么样的

上面已经可以完成转盘从转到停止的操作,如果需要在转之后,还有旋转的次数,可以加上下面的代码

 // 关闭弹框
    setData(dialogName, handle) {
       this.run = false
       this.rotateAngle = 0  
       this.rewardMaskVisible = false
    },
    // 等待n秒之后再弹
    sleep(time){
      return new Promise(function(resolve){
        setTimeout(resolve, time)
      })
    },
    // 完成旋转之后,弹起弹框
    async finishRotate() {
      await this.sleep(1000)
      this.rewardDetailVisible = true
    },
    
复制代码

这里的finishRotate实际是当转盘转完时,有一个transitionend的监听事件

<img
  :style="`${!run ? '' : rotateStyle}`"
  class="turntable-img"
  src="@/assets/image/juneTurntable/turntable-center.png"
  @transitionend="finishRotate"
>
复制代码

3.先永动,点击之后再抽奖,再永动的抽奖方式

之前我们的抽奖包括到抽奖按钮都是静止的,所以从视觉上可能达不到吸引用户去掉的一种效果,于是把点击抽奖按钮变成动态,让转盘进来就慢慢的转

抽奖2.gif

考虑过2种方法,第一种是先用animation: rotate 15s linear infinite做永动,点击时先置为0再旋转,这样会在页面上有一种重置的效果,所以采用第二种用定时器做永动

this.rotateAngle = 0
await this.sleep(0)
this.rotateAngle = this.config.circle * 360 - (30 + this.drawIndex * 60)
复制代码
代码(在上面的基础上添加或者修改)
 <img
  :style="`${normalRotateStyle} ${!run ? '' : rotateStyle}`"
  :class="['turntable-img', {'normal': normalTranstion}]"
  src="@/assets/image/juneTurntable/turntable-center.png"
  @transitionend="finishRotate"
> 
.turntable-img {
    width: 524px;
    height: 524px;
    &.normal{
      transition: transform 1s linear; 
    }
}
复制代码
data() {
    return {
      normalRotateAngle: 0,
      normalTranstion: true,
    }
},
computed: {
    rotateStyle () {
      const config = this.config
      console.log(this.rotateAngle, 78979)
      return `
        -webkit-transition: transform ${config.duration}ms ${config.mode};
        transition: transform ${config.duration}ms ${config.mode};
        -webkit-transform: rotate(${this.rotateAngle}deg);
            transform: rotate(${this.rotateAngle}deg);`
    },
    normalRotateStyle () {
      return `transform: rotate(${this.normalRotateAngle}deg);`
    },
},
async mounted() {
    this.$loading.show()
    try {
      await this.getActivity21StJuneInfo()
    } finally {
      this.$loading.hide()
    } 
    this.initNormalRotate()
},
methods: {
    initNormalRotate () {
      this.t = setInterval(() => {
        this.normalRotateAngle += 10
        this.normalTranstion = true
      }, 500) 
    },
    // 开始转动
   async startPlay() {
      if (!this.checkToken()) return //这里我们做了一个判断是否登录的操作,不需要的可以去掉
      if (+this.rotateAngle > 0) {
        this.$toast('正在抽奖中请不要重复点击')
        return 
      }
      if (+this.juneInfoStatusObj.residueCount === 0) {
        this.$toast('操作已达到上限')
        return
      }
      await this.getActivity21StJuneLottery()
      clearInterval(this.t)
      this.normalTranstion = false
      this.run = true
      this.rotateAngle = this.config.circle * 360 - (30 + this.drawIndex * 60)
    },
    // 通用修改data函数
    setData(dialogName, handle) {
        this.run = false
       this.rotateAngle = 0  
       this.rewardMaskVisible = false
       this.initNormalRotate()
       this.getActivity21StJuneInfo()
     },
     // 完成旋转之后,弹起弹框
    async finishRotate() {
      if (!this.run) {
        return
      }
      await this.sleep(1000)
      this.rewardDetailVisible = true
      this.run = false
      this.normalRotateAngle = 0
      this.rotateAngle = 0
    },
 },
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享