轉盤類型抽獎如何實現 需求

需求

常規轉動,如ease-in-out

這種方案適合已經得知中獎信息,得到旋轉角度,直接旋轉就ok

:style="{transform:rotate(360deg),transition:rotate_transition}"

transform:旋轉的角度

transition:過渡方式。如:'transform 3s ease-in-out'

mark transition需要事件觸發,所以沒法在網頁加載時自動發生。所以,只要讓transfor或transition變動一次,動畫就會執行一次

🙋🏻♀️:點擊開始,給style賦值就ok了。transform每次賦值只有不一樣,纔會動。這就是transition的含義:過渡

rotate_deg = 'rotate(360deg)'

rotate_transition = 'transform 3s ease-in-out'

隨機控制開始-旋轉-結束

上面的方案適合內定中獎名單,不用考慮接口請求,😈。但如果要是隨機中獎呢:開始抽獎,去向接口要中獎信息,接口返回中獎獎品,再決定轉盤旋轉多少。這種旋轉時間是不一定的。啥時候結束旋轉取決於接口什麼時候返回。

效果:啓動 - 加速 - 勻速 - 減速 - 停止

mark 動畫效果取決於transform:結束到開始的差值,duration內執行完。。結束值大於初始值,就是正轉。反之是反轉

封裝js控制工具

  • rotate.js
/**
 * mark: 入參interval都是秒,這裏具體用到的地方*1000了
 * @param el 入參需要旋轉的標籤元素
 * @param stepDeg 標籤元素step時間需要旋轉的角度 360度是一圈
 */
export function doInifityRotate(el) {
  // 每一次的旋轉,記錄旋轉的deg,下次更新style需要在totaldeg累加,規則:如果是大於totaldeg,正轉。如果小於totaldeg,反轉
  var hasDeg = 0
  // 每一次的旋轉,記錄已經旋轉的時間
  var hasDura = 0

  var easeInImpl = (function() {
    return function($el, duration, deg) {
      hasDeg += deg
      hasDura += duration
      $el.style = 'transform:rotate(' + hasDeg + 'deg);' + 'transition:transform ' + duration + 's ease-in'
    }
  })()

  var interval
  var linearForeverImpl = (function() {
    return function($el, stepInterval, stepDeg) {
      interval = setInterval(() => {
        hasDeg += stepDeg
        hasDura += stepInterval
        $el.style = 'transform:rotate(' + hasDeg + 'deg);' + 'transition:transform ' + stepInterval + 's linear'
      }, (stepInterval * 1000))
      console.log('=====interval ' + interval)
    }
  })()

  var linearImpl = (function() {
    return function($el, duration, deg) {
      hasDeg += deg
      hasDura += duration
      $el.style = 'transform:rotate(' + hasDeg + 'deg);' + 'transition:transform ' + duration + 's linear'
    }
  })()

  var easeOutImpl = (function() {
    return function($el, duration, deg, targetDeg, callBack) {
      if (interval) {
        clearInterval(interval)
      }
      // 1、指定的多轉的角度
      hasDeg += deg
      hasDura += duration
      // 2、向上取整到360度的倍數
      const lackDeg = 360 - (hasDeg % 360)
      hasDeg += lackDeg
      // 3、角度落到具體扇區
      hasDeg -= targetDeg
      $el.style = 'transform:rotate(' + hasDeg + 'deg);' + 'transition:transform ' + duration + 's ease-out'
      setTimeout(() => {
        callBack()
      }, (duration * 1000 + 50))
    }
  })()

  var stopImpl = (function() {
    return function($el) {
      console.log(hasDura)
      if (interval) {
        clearInterval(interval)
      }
      hasDura = 0
      hasDeg = 0
      $el.style = ''
    }
  })()

  return {
    easeIn: function(duration, deg) {
      // resetImpl(el)
      console.log('=== ease in')
      easeInImpl(el, duration, deg)
    },
    linearForever: function(stepInterval, stepDeg) {
      linearForeverImpl(el, stepInterval, stepDeg)
    },
    linear: function(duration, deg) {
      linearImpl(el, duration, deg)
    },
    /**
     *
     * @param duration 動畫時長
     * @param deg 動畫角度
     * @param targetDeg 0度起到獎品落到的角度。比如 需要把指針落到第二個扇區,那就需要多轉45度
     */
    easeOut: function(duration, deg, targetDeg, callBack) {
      easeOutImpl(el, duration, deg, targetDeg, callBack)
    },
    stop: function() {
      stopImpl(el)
    }
  }
}

  • 使用
// 開始請求網絡 獲取本次抽獎中獎信息
      this.prize()

// 轉盤控制組件
      var rotate = doInifityRotate(this.$refs['wheel'])
      
// 開始旋轉:加速旋轉
      rotate.easeIn(2, 720)
// 加速2s後,開始勻速旋轉
      setTimeout(() => {
        rotate.linearForever(0.01, 6)
      }, 2000)

// 此間,持續關注着網絡請求結果。這裏控制了閾值4s
      var interval
      var time = 0
      interval = setInterval(() => {
        time++
        if (Object.keys(this.raffledPrize).length > 0) {
          // 抽到獎了
          clearInterval(interval)
          const that = this
          // 具體的獎品在獎盤上的位置角度
          const targetDeg = this.getTargetDeg()
          
          if (time > 4000) {
          // 減速旋轉,直到結束,停到獎品對應的角度位置
            rotate.easeOut(2.5, 720, targetDeg, function() {
            // 中獎後的操作
              that.wheelOver()
            })
          } else {
          // 這裏表示,如果網絡請求很快,從開始旋轉到中獎結果回來,不夠4s,那就轉夠4s。然後開始減速-結束
            setTimeout(() => {
              rotate.easeOut(2.5, 720, targetDeg, function() {
                that.wheelOver()
              })
            }, (4000 - time))
          }
        } else if (this.raffleError) {
          // 抽獎請求失敗
          clearInterval(interval)
          const that = this
          setTimeout(() => {
            rotate.stop()
            that.isAllowClick = true
          }, 2100)
        }
      }, 1000)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章