需求
常規轉動,如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)