使用vue+grid布局
看看效果
- 准备mock数据
- 转盘的基本布局
- 借助grid调整我们按钮位置
- 开始抽奖
首先mock我们的中奖数据,中奖标识、奖品介绍、奖品图片等等。
const JP_OPTIONS = [
{
code: '1',
name: '奖品1',
imageName: '3q', //换上自己的img name
},
...
]
基本布局方案,将我们的抽奖按钮项放置最后一位,借助index下标给我们的li定义不同的class name。
<template>
<div class="dp-wrap">
<ul class="u-wrap">
<li
v-for="(jp, index) in jpList"
:key="jp.code"
:class="[{ active: jpIndex == index }, 'li-w-' + index]"
>
<img :src="jp.requireUrl" />
</li>
<!-- 将抽奖按钮放在最后一位 -->
<li class="now-w" @click="onStart"></li>
</ul>
</div>
</template>
挂载mock数据,实际是请求后端接口的数据。
export default {
data() {
let jpList = JP_OPTIONS.map((item) => {
item.requireUrl = require(`@/assets/${item.imageName}.png`) //加载本地的资源文件并转成base64
return item
})
return {
jpList,
jpIndex: 0, //抽奖开始项
}
}
}
grid布局, 资源加载可换成自己的图片,这时候我们可以借助grid布局任意组合我们的行和列,以便于我们调整li的位置。
@mixin li-w($gcs, $gce, $grs, $gre) {
grid-column-start: $gcs;
grid-column-end: $gce;
grid-row-start: $grs;
grid-row-end: $gre;
}
.dp-wrap {
position: absolute;
top: 0.4rem;
left: 0.4rem;
right: 0.4rem;
// height: 6.82rem;
background: url('~@/assets/dp.png');
background-size: 100% 100%;
background-repeat: no-repeat;
padding: 0.34rem 0.34rem 0.52rem 0.34rem;
box-sizing: border-box;
.u-wrap {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, 1fr);
grid-gap: 0.04rem 0.04rem;
.active {
background: url('~@/assets/win.png');
background-size: 100% 100%;
background-repeat: no-repeat;
}
> li {
background: url('~@/assets/fail.png');
background-size: 100% 100%;
background-repeat: no-repeat;
display: grid;
grid-auto-flow: row;
justify-content: center;
justify-items: center;
align-content: center;
padding: 0.2rem 0 0.32rem;
> p {
font-size: 0.2rem;
color: #3d79f3;
margin-top: 0.14rem;
text-align: center;
}
> img {
// width: 100%;
max-height: 0.94rem;
}
}
/**/
.li-w-3 {
@include li-w(3, 4, 2, 3);
}
.li-w-4 {
@include li-w(3, 4, 3, 4);
}
.li-w-5 {
@include li-w(3, 4, 4, 5);
}
.li-w-6 {
@include li-w(2, 3, 4, 5);
}
.li-w-7 {
@include li-w(1, 2, 4, 5);
}
.li-w-8 {
@include li-w(1, 2, 3, 4);
}
.li-w-9 {
@include li-w(1, 2, 2, 3);
}
.now-w {
background: url('~@/assets/jp.png');
background-size: 100% 100%;
background-repeat: no-repeat;
@include li-w(2, 3, 2, 4);
}
}
}
接下来,借助JavaScript里的装饰者模式让转盘转动起来。
//定义一个class来维护我们的转动轨迹
class Luck {
constructor() {
this.index = 0; //当前转动到哪个位置,起点位置
this.count = 10; //总共有多少个位置
this.timer = 0; //setTimeout的ID
this.speed = 20; //初始转动速度
this.times = 0; //转动次数
this.cycle = 50; //转动基本次数:即至少需要转动多少次再进入抽奖环节
this.prize = -1; //中奖位置
this.code = ''; //中奖奖品code
}
init(count, index) {
if (count > 0) {
this.count = count;
this.index = index
}
}
roll() {
let index = this.index;
let count = this.count;
index += 1;
if (index > count - 1) {
index = 0;
}
this.index = index;
return index;
}
}
export default new Luck();
//onStart方法就是点击开始抽奖执行的
onStart() {
luck.init(this.jpList.length, this.jpIndex)
const test = '5' //test就是我们后端返回的中奖项code,现在我们模拟让他是5
luck.prize = this.jpList.findIndex((item) => item.code === test) //匹配到我们的中奖项
luck.code = test
luck.speed = 100
this.roll()
}
roll() {
luck.times += 1
this.jpIndex = luck.roll()
if (luck.times > luck.cycle + 10 && luck.prize == luck.index) {
clearTimeout(luck.timer)
luck.prize = luck.prize
luck.times = 0
//已经中奖啦,这个时候就可以做我们中奖后的事情啦。。。
} else {
if (luck.times < luck.cycle) {
luck.speed -= 10
} else if (luck.times == luck.cycle) {
luck.prize = luck.prize //最终中奖位置
} else {
if (
luck.times > luck.cycle + 10 &&
((luck.prize == 0 && luck.index == 7) ||
luck.prize == luck.index + 1)
) {
luck.speed += 110
} else {
luck.speed += 20
}
}
if (luck.speed < 40) {
luck.speed = 40
}
luck.timer = setTimeout(this.roll, luck.speed)
}
},
这样整个抽奖轮盘就可以转动起来了。
[grid布局参考]:(www.ruanyifeng.com/blog/2019/0…)