想尽快的复制结果,看标题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);
}
复制代码
显示效果是:
所以我们应该改成:
<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>
复制代码
2.实现静态转盘的抽奖
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种方法,第一种是先用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
},
},
复制代码