新年将至,先提早祝你们新年快乐万事如意,想必不少人已经开过了一个记忆深入或者毫无趣味的年会了,那么,迟来的抽奖组件来了,233333333css
先来看看要使用到的一些dataios
data () {
return {
bgStatus: true, // 控制抽奖边框的闪烁
bgInterval: '', // 存放背景切换的setInterval,方便组件销毁时清除任务
prizeList: [], // 用于渲染的奖品列表
idList: [], // 用于存放奖品id的数组
cur: undefined, // 当前步对应的项
speed: 100, // 速度
couldClick: true // 控制抽奖按钮可点击状态
}
}
复制代码
先看看data的一个结构,用到的变量注释了,后面若是有疑问的能够到这边来看axios
看下咱们的template结构api
<template>
<div class="md-div">
<!-----------跑马灯------------->
<div class="md-bd-bg" :class="bgStatus ? 'md-bd-bg1' : 'md-bd-bg2'">
<!----------抽奖容器-------------->
<div class="item-out">
<!----------循环奖项-------------->
<div class="prize-item flex-column flex-just-center flex-align-center" v-for="k in prizeList" :key="k.prizeid"
:class="k.prizeid === cur ? 'prize-y' : 'prize-n'"
>
<div class="prize-img flex-row flex-just-end flex-align-center">
<img :src="`https://${k.photo}`" alt="">
</div>
<!-- <div class="prize-word">{{k.prize_name}}</div>-->
</div>
<!-----------抽奖按钮------------->
<div class="prize-btn" @click="doPrize" :class="couldClick ? '' : 'refuse-click'"></div>
</div>
</div>
</div>
</template>
复制代码
分析一下结构,咱们给了一个外层(class=md-bd-bg),用做外层灯光的闪烁控制,这里很简单,咱们须要的只是两张图几乎同样的背景图数组
.md-bd-bg1{background-image: url("../../statics/tbIcon/shine1.png")}
.md-bd-bg2{background-image: url("../../statics/tbIcon/shine2.png")}
.md-bd-bg{
width: 100%;
height: 100%;
background-size: 100% 100%;
padding: 6vw;
}
复制代码
这就是外边框的样式,md-bd-bg1和md-bd-bg2分别对应了两个状态,下一步就是要让他动起来bash
controlBg () { // 背景变换函数
let vm = this
vm.bgInterval = setInterval(() => {
vm.bgStatus = !vm.bgStatus
}, 500)
}
复制代码
methods当中的一个方法,咱们用bgInterval存放了一个setInterval,之因此要用一个变量存储,是为了在清除组件的时候清除事件dom
终于到了咱们正儿八经的跑马灯抽奖了,先分析结构函数
<!----------循环奖项-------------->
<div class="prize-item flex-column flex-just-center flex-align-center" v-for="k in prizeList" :key="k.prizeid"
:class="k.prizeid === cur ? 'prize-y' : 'prize-n'"
>
<div class="prize-img flex-row flex-just-end flex-align-center">
<img :src="`https://${k.photo}`" alt="">
</div>
<!-- <div class="prize-word">{{k.prize_name}}</div>-->
</div>
复制代码
使用v-for将请求到的奖品数组循环渲染flex
.prize-y{background-image: url("../../statics/tbIcon/prize_y.png");}
.prize-n{background-image: url("../../statics/tbIcon/prize_n.png")}
.prize-item:nth-of-type(1){top: .1vw;left: .1vw;}
.prize-item:nth-of-type(2){top: .1vw;left: 27.35vw;}
.prize-item:nth-of-type(3){top: .1vw;left: 54.6vw;}
.prize-item:nth-of-type(4){top: 27.35vw;left: 54.6vw;}
.prize-item:nth-of-type(5){top: 54.6vw;left: 54.6vw;}
.prize-item:nth-of-type(6){top: 54.6vw;left: 27.35vw;}
.prize-item:nth-of-type(7){top: 54.6vw;left: .1vw;}
.prize-item:nth-of-type(8){top: 27.35vw;left: .1vw;}
复制代码
这里用到了vw单位,vw和vh、vmin、vmax这几个,不说了,用了都说香,上面的代码将奖项摆放成了一个圈,留下了按钮的空间,下面是点击按钮的css动画
.prize-btn{width: 27vw;height: 27vw;background-size: 100% 100%;position: absolute;background-image: url("../../statics/tbIcon/prize-btn.png");top:27.35vw;left:27.35vw;}
复制代码
好啦,东西摆放好了,咱们愉快地开始写逻辑吧
看看咱们的抽奖按钮
<template>
<div class="prize-btn" @click="doPrize" :class="couldClick ? '' : 'refuse-click'"></div>
</template>
/*------------------禁止点击-------------*/
.refuse-click{filter: grayscale(10%);}
||
\||/
\/
doPrize () {
let vm = this
if (vm.couldClick) {
vm.couldClick = false // 禁止第一次抽奖没执行完又进行下一次抽奖
vm.$axios(urls.doPrize, {}).then(res => {
let code = res.code
if (code === 'success') {
vm.prizeAnimate(res)
} else {
vm.$q.notify({ message: res.msg })
}
})
}
}
复制代码
这里给了按钮一个动态class,让它在可点击的时候是设计图上的原色,不可点击的时候则加上灰色的滤镜,讲道理,css的filter也是真的香,有兴趣的同窗能够去看看,能够看到点击了抽奖按钮后,并非直接执行prizeAnimate,而是先向服务请求了抽奖结果,也就是说,后面的动画都是多余的,你点击的时候已经决定了你的中奖结果,因此咱们不写动画了,就这样就能够直接用了
开个玩笑 粘上个人抽奖动画代码
prizeAnimate (result) {
let vm = this
vm.cur = undefined
let num = vm.idList.indexOf(Number(result.prizeid))
let len = vm.idList.length
let allSteps = Math.floor(Math.random() * 3 + 2) * len + num // 总共要走的步数 2~5圈
let a = 0
function myInt () {
setTimeout(() => {
if (a <= allSteps) { // a是已经跳动的步数
if (allSteps - a < len * 2 && allSteps - a >= len) { // 进入倒数第二圈,增长延时
vm.speed = 200
} else if (allSteps - a < len) { // 进入倒数第一圈,再次增长延时
vm.speed = 400
}
vm.cur = vm.idList[a % vm.idList.length] // 当前跳至的奖项能够用步数除以奖品数组长度求余便可
a++ // 执行完跳动后记得将已跳动步数加1
myInt() // 递归调用
} else { // 终于跳完了
vm.couldClick = true // 解除对按钮的限制
vm.speed = 100 // 将速度还原
// -------
// 抽奖动画执行完接下来的操做,好比说弹窗通知中奖
}
}, vm.speed)
}
myInt()
}
}
复制代码
拿到了抽奖结果,第一步,咱们将cur清空了,接着取出中奖结果在奖品数组里的index值,也就是num 此处的allSteps用来生成总共须要走的步数,为了让动画尽量看起来‘咱们是真的用动画抽了的噢’,因此设置了2到5圈再加上前面求到的index值, 那么如今咱们就知道了总共要走的步数
这里我声明了myInt函数用做递归执行setTimeout的函数体,这样作的目的,首先,咱们的抽奖是有动画的,因此速度确定不能匀速,若是使用setInterval,那么变动speed并不会改变更画的跳动速度,其次嘛,setInterval其实也能够用,可是你得写三个,一个快速的,一个中速的,一个低速的,而后挨个执行,你看我大setTimeout递归调用,不香吗,代码量很多吗!哈哈,原本想再解释一下这段函数,可是感受都写在备注里了,那就这样吧,我要收拾收拾回家过年了,886~~
<template>
<div class="md-div">
<div class="md-bd-bg" :class="bgStatus ? 'md-bd-bg1' : 'md-bd-bg2'">
<div class="item-out">
<div class="prize-item flex-column flex-just-center flex-align-center" v-for="k in prizeList" :key="k.prizeid"
:class="k.prizeid === cur ? 'prize-y' : 'prize-n'"
>
<div class="prize-img flex-row flex-just-end flex-align-center">
<img :src="`https://${k.photo}`" alt="">
</div>
<!-- <div class="prize-word">{{k.prize_name}}</div>-->
</div>
<!-----------抽奖按钮------------->
<div class="prize-btn" @click="doPrize" :class="couldClick ? '' : 'refuse-click'"></div>
</div>
</div>
</div>
</template>
<script>
import urls from 'src/api/urls'
export default {
name: 'module',
data () {
return {
bgStatus: true,
bgInterval: '',
prizeList: [], // 奖品列表
idList: [],
cur: undefined, // 当前帧对应的项
speed: 100,
couldClick: true // 抽奖按钮可点击
}
},
created () {
let vm = this
vm.controlBg() // 开启背景变换
vm.queryList() // 请求奖项
},
methods: {
controlBg () { // 背景变换函数
let vm = this
vm.bgInterval = setInterval(() => {
vm.bgStatus = !vm.bgStatus
}, 500)
},
queryList () {
let vm = this
vm.$axios(urls.getPrizeList, {}).then(res => {
let code = res.code
if (code === 'success') {
// console.log(res)
for (let k in res.lottery_prize) {
vm.idList.push(res.lottery_prize[k].prizeid)
}
vm.prizeList = res.lottery_prize
vm.$emit('subNotice', res)
} else {
vm.$router.go(-1)
}
})
},
doPrize () {
let vm = this
if (vm.couldClick) {
vm.couldClick = false // 禁止下次当即执行
vm.$axios(urls.doPrize, {}).then(res => {
let code = res.code
if (code === 'success') {
vm.prizeAnimate(res)
} else {
vm.$q.notify({ message: res.msg })
}
})
}
},
prizeAnimate (result) {
let vm = this
vm.cur = undefined
let num = vm.idList.indexOf(Number(result.prizeid))
let len = vm.idList.length
let allStamps = Math.floor(Math.random() * 3 + 2) * len + num // 总共要走的步数 2~5圈
let a = 0
function myInt () {
setTimeout(() => {
if (a <= allStamps) {
if (allStamps - a < len * 2 && allStamps - a >= len) {
vm.speed = 200
} else if (allStamps - a < len) {
vm.speed = 400
}
vm.cur = vm.idList[a % vm.idList.length]
a++
myInt()
} else {
vm.couldClick = true
vm.$emit('subDc', result)
vm.speed = 100
}
}, vm.speed)
}
myInt()
}
}
}
</script>
<style scoped>
.md-div{
width: 94vw;
height: 94vw;
position: relative;
margin: 3vw;
}
.md-bd-bg1{background-image: url("../../statics/tbIcon/shine1.png")}
.md-bd-bg2{background-image: url("../../statics/tbIcon/shine2.png")}
.md-bd-bg{
width: 100%;
height: 100%;
background-size: 100% 100%;
padding: 6vw;
}
.item-out{width: 100%;height: 100%;position: relative;}
.prize-item{
width: 27vw;
height: 27vw;
background-size: 100% 100%;
position: absolute;
}
.prize-btn{width: 27vw;height: 27vw;background-size: 100% 100%;position: absolute;background-image: url("../../statics/tbIcon/prize-btn.png");top:27.35vw;left:27.35vw;}
.prize-img{width: 70%;height: 40%;}
.prize-img img{width: 100%;height: auto;}
.prize-word{color: #832909;font-size: 1.4rem;}
.prize-y{background-image: url("../../statics/tbIcon/prize_y.png");}
.prize-n{background-image: url("../../statics/tbIcon/prize_n.png")}
.prize-item:nth-of-type(1){top: .1vw;left: .1vw;}
.prize-item:nth-of-type(2){top: .1vw;left: 27.35vw;}
.prize-item:nth-of-type(3){top: .1vw;left: 54.6vw;}
.prize-item:nth-of-type(4){top: 27.35vw;left: 54.6vw;}
.prize-item:nth-of-type(5){top: 54.6vw;left: 54.6vw;}
.prize-item:nth-of-type(6){top: 54.6vw;left: 27.35vw;}
.prize-item:nth-of-type(7){top: 54.6vw;left: .1vw;}
.prize-item:nth-of-type(8){top: 27.35vw;left: .1vw;}
/*------------------禁止点击-------------*/
.refuse-click{filter: grayscale(10%);}
</style>
复制代码