做了各种各样的营销抽奖活动,有九宫格抽奖、大转盘抽奖、滚动抽奖、刮刮卡抽奖,来总结一波~
九宫格抽奖
我们先来看下最终实现的效果:
思路
我们需要定义九个格子,抽奖按钮放在最中间,使用flex
来实现布局,摆放顺序是z
字形,但是我们抽奖是顺时针转动的,所以要注意下奖品的摆放顺序。
点击抽奖的时候,我们需要请求后台接口,后台会返回给我们抽中的奖品,也就是九宫格转动最终要停下来的位置,为了让效果看起来更好看,会默认先让转盘转几圈,然后再转动到奖品位置停下。转动效果是通过定时器依次改变每个格子的背景颜色来实现的。抽奖转动效果一般是速度慢慢加快或者匀速,然后再慢慢减慢直至停止到奖品位置处。
实现
先来写静态页面:
<div id="app">
<div class="lottery__list">
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 0}">1</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 1}">2</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 2}">3</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 7}">8</div>
<div class="lottery__item btn" @click="handleLottery">抽奖</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 3}">4</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 6}">7</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 5}">6</div>
<div class="lottery__item" :class="{'lottery__item--active':activeIndex === 4}">5</div>
</div>
</div>
动态定义了一个lottery__item--active
的class
,转动效果就是通过这个class
实现的,activeIndex
是当前转动到的格子的索引,转盘从第一个格子开始顺时针转动。
样式:
<style>
.lottery__list {
display: flex;
flex-wrap: wrap;
width: 184px;
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
}
.lottery__item {
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
.lottery__item--active {
background-color: red;
}
.btn {
cursor: pointer;
}
</style>
vue
实现:
通过上面的分析我们知道,我们需要定义好以下几个变量:最终的奖品位置、目前转动的步数、最终停下来的目标步数、转动的速度、定时器ID。
<script>
const { createApp, reactive, toRefs, computed } = Vue
createApp({
setup() {
const state = reactive({
lottery: 0, // 奖品
step: -1, // 目前转动的步数
stopStep: 32, // 目标步数,上面我们有提到默认都会转几圈,这里默认转四圈,一圈有八个格子,四圈就是要转动32步
speed: 2, // 转动速度,我们是通过定时器去实现转动效果的,所以这也就是定时器的执行频率
timer: 0, // 定时器ID
loading: false
})
// 通过目前转动的步数来对8取模得到当前转到的格子索引
const activeIndex = computed(() => {
return state.step % 8
})
// 点击抽奖之后调用的函数
function handleLottery() {
if(state.loading) return
state.loading = true
// 最终获得的奖品,实际业务中是通过接口获取的,这里使用随机数来模拟下
state.lottery = Math.floor(Math.random() * 8)
console.log(state.lottery)
// 计算总共要转动的步数,转4圈后再转到奖品处
state.stopStep = state.lottery + 32
// 执行抽奖函数
timer = runFn()
}
function runFn() {
// 抽奖函数
}
return {
...toRefs(state),
activeIndex,
handleLottery
}
}
}).mount('#app')
</script>
接下来来实现抽奖函数,抽奖函数最终要实现的就是通过定时器不停的去增加step
直到目标步数,那速度怎么控制呢?通过改变定时器的执行时间来控制:
function runFn() {
// 当前步数大于等于目标步数
if (state.step >= state.stopStep) {
// 清空定时器,停止转动
clearTimeout(state.timer)
// 将初始化步数为最终奖品的步数,转动速度也置为初始速度,下次才能正确转动
state.step = state.lottery
state.speed = 2
state.loading = false
alert(`恭喜获得${state.lottery + 1}号奖品`)
return
}
// 转动到最后一圈时,增加speed,也就是定时器执行间隔时间变长,转动速度变慢
if (state.step > (24 + state.lottery)) {
state.speed++
}
// 抽奖函数每执行一次,当前步数加一
state.step++
// 重新开启定时器执行抽奖函数
timer = setTimeout(runFn, state.speed * 30)
}
大转盘抽奖就实现拉~具体的实现还是要根据实际业务来,另外可以试试用requestAnimationFrame
来替换setTimeout
,优化动画效果。
下一篇来实现:大转盘抽奖