需求
常规转动,如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)