做了各种各样的营销抽奖活动,有九宫格抽奖、大转盘抽奖、滚动抽奖、刮刮卡抽奖,来总结一波~
大转盘抽奖
我们先来看下最终实现的效果:
思路
一般奖品都是固定的,所以UI会设计好一个有奖品的大转盘给你,但如果奖品列表是后台随机返回的,那就需要自己用css来实现大转盘。本文是通过css来实现的。
大转盘抽奖可以转动盘子,中间的指针不动;也可以转动指针,盘子不动。但是实现原理是一样的,改变旋转角度。本文实现的是转动中间的指针。
实现
先来写静态页面:
<div id="app">
<div class="lottery__list">
<div class="lottery__item" v-for="(item,index) in 10">
<div class="inner">
<span>奖品{{index + 1}}</span>
</div>
</div>
<div ref="pointer" class="pointer" @click="handleLottery">开始抽奖</div>
</div>
</div>
页面很简单,样式稍微有点复杂,大转盘是由10个扇形组成的,每个扇形的角度是36deg。我们先来看张图:
一个矩形(矩形长 = 矩形宽 * 2),一个半圆形(直径 = 矩形长),半圆形和矩形对齐,然后以中心点为旋转中心开始旋转,我们可以看到半圆形和矩形相交的部分就是扇形。将矩形不设置背景色并且超出隐藏,半圆形设置背景色,半圆形旋转ndeg,就可以得到ndeg的扇形。下面我们通过代码来实现下:
// 样式
<style>
.lottery__item {
width: 200px;
height: 100px;
position: relative;
overflow: hidden;
}
.inner {
position: absolute;
width: 200px;
height: 100px;
top: 100%;
background: #ff6b6b;
border-radius: 0 0 100px 100px;
transform-origin: top center;
transform: rotate(36deg);
box-sizing: border-box;
}
</style>
// html页面
<body>
<div class="lottery__item">
<div class="inner">
</div>
</div>
</body>
扇形已经知道了怎么实现的,接下来我们来实现大转盘:
<style>
.lottery__list {
position: relative;
width: 200px;
height: 200px;
border: 2px solid #ff5555;
border-radius: 50%;
}
.lottery__item {
position: absolute;
top: 0;
left: 100px;
width: 100px;
height: 200px;
overflow: hidden;
transform-origin: left center;
}
.inner {
position: absolute;
top: 0;
left: -100px;
width: 100px;
height: 200px;
padding: 5px 3px 0 57px;
border-radius: 100px 0 0 100px;
transform: rotate(36deg);
transform-origin: right center;
font-size: 12px;
box-sizing: border-box;
}
.inner span {
display: block;
transform-origin: center;
transform: rotate(-19deg);
}
.lottery__item:nth-child(2n+1) .inner {
background: #fef6e0;
}
.lottery__item:nth-child(2n) .inner {
background: #ffffff;
}
.lottery__item:nth-child(1) {
display: block;
transform: rotate(-18deg);
}
.lottery__item:nth-child(2) {
transform: rotate(18deg);
}
.lottery__item:nth-child(3) {
transform: rotate(54deg);
}
.lottery__item:nth-child(4) {
transform: rotate(90deg);
}
.lottery__item:nth-child(5) {
transform: rotate(126deg);
}
.lottery__item:nth-child(6) {
transform: rotate(162deg);
}
.lottery__item:nth-child(7) {
transform: rotate(198deg);
}
.lottery__item:nth-child(8) {
transform: rotate(234deg);
}
.lottery__item:nth-child(9) {
transform: rotate(270deg);
}
.lottery__item:nth-child(10) {
transform: rotate(306deg);
}
.pointer {
position: absolute;
left: 79px;
top: 79px;
width: 30px;
height: 30px;
padding: 6px;
background-color: #ff5350;
border: 1px solid #ff5350;
border-radius: 50%;
transition: transform 3s cubic-bezier(.2, .93, .43, 1);
line-height: 15px;
font-size: 12px;
text-align: center;
}
.pointer::after {
content: '';
position: absolute;
left: 14px;
top: -24px;
border-width: 12px 6px;
border-style: solid;
border-color: transparent;
border-bottom-color: #ff5350;
transform-origin: center;
}
</style>
vue实现:
上面的样式中,我们已经给中间的指针设置了旋转动画了,所以我们需要请求后台接口拿到奖品,然后设置相应的旋转角度即可。
<script>
const { createApp, reactive, ref, toRefs, computed, onMounted } = Vue
createApp({
setup() {
const state = reactive({
lottery: 0, // 本次抽奖的奖品索引
lastLottery: 0, // 上一次抽奖的奖品索引
stopDeg: 0, // 最终要旋转的角度
loading: false
})
const pointer = ref()
function handleLottery() {
if(state.loading) return
state.loading = true
// 最终获得的奖品索引,实际业务中是通过接口获取的,这里使用随机数0~9来模拟下
state.lottery = Math.floor(Math.random() * 10)
console.log(state.lottery)
// 最终的旋转角度,指针指向本次奖品的旋转角度+指针从上一次的奖品指向回归0的旋转角度+ 默认转动三圈
state.stopDeg += (state.lottery + (10 - state.lastLottery)) * 36 + 1080
// 旋转
pointer.value.style.transform = `rotate(${state.stopDeg}deg)`
}
onMounted(() => {
// 旋转动画结束,弹出奖品
pointer.value.addEventListener('transitionend', () => {
alert(`恭喜获得奖品${state.lottery + 1}`)
// 保留奖品索引
state.lastLottery = state.lottery
state.loading = false
})
},[])
return {
...toRefs(state),
pointer,
handleLottery
}
}
}).mount('#app')
</script>