新年將至,先提早祝你們新年快樂萬事如意,想必不少人已經開過了一個記憶深入或者毫無趣味的年會了,那麼,遲來的抽獎組件來了,233333333css
先來一張效果圖,哈哈,不是什麼年會大抽獎,只是一個跑馬燈抽獎組件,233333,明年年會前,必定寫一篇年會用的抽獎先來看看要使用到的一些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>
複製代碼