效果图:
直接上代码:
<template>
<div class="flex p-5">
<div class="lists">
<div
class="list"
:class="{ 'start-btn': item.level === 0, disabled: item.level === 0 && isRunning, active: activeIndex === index }"
@click="listClick(item.level)"
:data-index="index"
v-for="(item, index) in prises"
:key="item.id"
>
<span class="name">
<span v-if="item.level > 0">{{ `${item.level}等奖:` }}</span>
<br />
<span class="name flex items-center justify-center text-xs">{{ item.name }}</span>
<br />
<span class="value" v-if="![0, 8].includes(item.level)">{{ `价值:¥${item.value}` }}</span>
</span>
</div>
</div>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
prises: [
{ name: '小牛电动车', level: 5, value: 2999 },
{ name: '2022 M2 MacBookPro 13寸', level: 1, value: 13999 },
{ name: '京东1000元购物卡', level: 6, value: 1000 },
{ name: 'iphone14 Pro Max', level: 2, value: 11999 },
{ name: '抽奖', level: 0 },
{ name: 'Ipad', level: 4, value: 4399 },
{ name: '京东500元购物卡', level: 7, value: 500 },
{ name: '谢谢惠顾', level: 8 },
{ name: 'HP 暗夜精灵7代', level: 3, value: 7999 }
],
winningOrder: 1, // 中几等奖
isRunning: false, // 是否正在抽奖
startSpeed: 150, // 初始动画速度
speed: '', // 动画实时速度
interval: null, // 定时器实例
maxAnimationTime: 4500, // 最大抽奖动画时长
activeIndex: '', // 当前走到的index
rorateArr: [0, 1, 2, 5, 8, 7, 6, 3], // 动画路径数组
rotateIndex: 0, // 路径数组走到第一格
startTime: '', // 开始时间
endTime: '' // 结束时间
}
},
computed: {
// 动画运行时长
rotateTime() {
return this.endTime - this.startTime
},
speedIntervalValue() {
return this.startSpeed / 10
}
},
created() {
this.getPrises()
},
methods: {
getPrises() {
this.prises.forEach((i) => {
i.id = this.randomId()
})
},
randomId() {
return Math.random()
},
listClick(level) {
if (level == 0) {
this.start()
}
},
// 抽奖
start() {
if (this.isRunning) {
return
}
this.isRunning = true
this.reset()
const timeout = setTimeout(() => {
this.intervalFn()
clearTimeout(timeout)
}, this.speed)
},
intervalFn() {
clearInterval(this.interval)
this.interval = null
if (!this.isRunning) {
return
}
// 变动画速度(逐渐加快)
this.speed -= this.speedIntervalValue
if (this.speed <= 50) {
// 最快速度
this.speed = 50
}
// 距离动画时间结束不到3秒时,动画逐渐减慢
if (this.maxAnimationTime - this.rotateTime <= 2000) {
this.speed += this.speedIntervalValue * 2 // 这里为什么加两倍,因为再次进入intervalFn方法,默认会减一倍,所以这里实际上是相当于加一倍
}
if (this.rotateTime > this.maxAnimationTime) {
// 超过时长了
if (this.winningOrder == this.prises[this.activeIndex].level) {
// 动画跑到了中奖奖品那
this.isRunning = false
console.log(`抽奖结束,奖品${this.winningOrder}等奖,用时:${(this.rotateTime / 1000).toFixed(2)}秒`)
return
}
}
this.rotate()
this.interval = setInterval(this.intervalFn, this.speed)
},
// 旋转高亮算法
rotate() {
if (this.rotateIndex === this.rorateArr.length) {
this.rotateIndex = 0
}
this.activeIndex = this.rorateArr[this.rotateIndex]
this.endTime = new Date().getTime()
this.rotateIndex += 1
},
// 重置
reset() {
this.startTime = new Date().getTime()
this.endTime = this.startTime
this.speed = this.startSpeed
this.rotateIndex = 0
}
}
}
</script>
<style lang="scss" scoped>
$primary-color: #2ca1f4;
.lists {
width: 500px;
height: 500px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.list {
position: relative;
width: 150px;
height: 150px;
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
background: #eee;
color: $primary-color;
&.active {
background: green;
color: #fff;
}
&.start-btn {
cursor: pointer;
color: #fff;
background: $primary-color;
&.disabled {
cursor: not-allowed;
background: #999;
}
}
.name {
text-align: center;
}
.image {
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
}
}
}
</style>