要完成一個這樣的抽獎功能css
使用 flex 來佈局,easy,當 curGameIdx
等於當前獎品 index
時高亮html
html前端
<div class="game-box">
<template v-for="(val, idx) of boundList">
<div v-if="idx == 4" class="game-item game-begin" :key="idx" @click="beginGame">
開始遊戲
</div>
<div v-else :key="idx" class="game-item" :class="{ active: idx === curGameIdx }">
{{val}}
</div>
</template>
</div>
複製代碼
cssvue
.game-box {
display: flex;
flex-wrap: wrap;
text-align: center;
.game-item {
width: 1.25rem;
height: 0.3rem;
background: yellow;
border: 1px solid transparent;
transition: all 0.2s;
&.game-begin {
background: transparent;
}
&.active {
border: 1px solid black;
}
}
}
複製代碼
效果圖 git
新建一個 Game
的 class
,有有個 run
方法和 finish
方法github
動畫的速度是變化的,使用 requestAnimationFrame
和 setInterval
有點不妥,因此:能夠使用 setTimeout
+ speed 參數
來控制動畫的速度。函數
class Game {
constructor(idx) {
this.idx = idx;
this.speed = 400;
}
addIdx(){
}
speedControl() {
}
finish() {
}
run(cb) {
this.speedControl();
setTimeout(() => {
this.addIdx();
!this.isFinish && this.run(cb);
}, this.speed);
}
}
複製代碼
收到結束運行的通知時,須要先作減速動畫,而後再中止在對應的 num
,而後調用回調函數,因此先暫存結束回調和結束點,並將動畫設置爲減速。佈局
finish(num, finishCb) {
this.oil = false;
this.endIdx = num;
this.finishCb = finishCb;
}
複製代碼
this.oil = true
)經過是否達到預期速度來中止加速,當減速時同理。speedUp() {
this.speed -= 60;
}
speedDown() {
this.speed += 200;
}
speedControl() {
if (this.speed > this.Max_Speed) {
if (this.oil) {
this.speedUp();
}
}
if (!this.oil) {
if (this.speed < this.Min_Speed) {
this.speedDown();
} else if (this.endIdx === this.idx) {
this.isFinish = true;
typeof this.finishCb === 'function' && this.finishCb();
}
}
}
複製代碼
此時,上面 UI 是經過 v-for
+ flex
展現的,而動畫的執行是轉圈,因此須要矯正 index
學習
更改上面 addIdx
方法,矯正 index,並將 ++index
取餘flex
constructor(idx) {
this.idx = idx;
this.speed = 400;
this.order = null;
this.Order_List = [0,1,2,5,8,7,6,3];
this.Game_Box_Num = 8;
}
addIdx() {
this.idx = (++this.idx % this.Game_Box_Num);
this.order = this.Order_List[this.idx];
}
複製代碼
將須要交互的函數傳遞給 Game
的實例便可
// vue 代碼
methods: {
updateGameIdx(order) {
this.curGameIdx = order;
},
gameFinish() {
this.playing = false;
console.log(this.curGameIdx, 'curGameIdx')
},
beginGame() {
if (this.playing) return;
this.playing = true;
this.curGameIdx = 0;
const game = new Game(this.curGameIdx);
game.run(this.updateGameIdx);
// 經過請求終止
setTimeout(() => {
game.finish(2, this.gameFinish)
}, 3000);
}
}
複製代碼
class Game {
constructor(idx) {
this.idx = idx;
this.speed = 400;
this.oil = true;
this.isFinish = false;
this.endIdx = null;
this.finishCb = function() {}
// 常量
this.Max_Speed = 100;
this.Min_Speed = 500;
this.Order_List = [0,1,2,5,8,7,6,3];
this.Game_Box_Num = 8;
}
speedUp() {
this.speed -= 60;
}
speedDown() {
this.speed += 200;
}
speedControl() {
if (this.speed > this.Max_Speed) {
if (this.oil) {
this.speedUp();
}
}
if (!this.oil) {
if (this.speed < this.Min_Speed) {
this.speedDown();
} else if (this.endIdx === this.idx) {
this.isFinish = true;
typeof this.finishCb === 'function' && this.finishCb();
}
}
}
finish(num, finishCb) {
this.oil = false;
this.endIdx = num;
this.finishCb = finishCb;
}
addIdx() {
this.idx = (++this.idx % this.Game_Box_Num);
}
run(cb) {
this.speedControl();
typeof cb === 'function' && cb(this.Order_List[this.idx]);
setTimeout(() => {
this.addIdx();
!this.isFinish && this.run(cb);
}, this.speed);
}
}
export default Game;
複製代碼
主要功能已經實現,想漂亮點再改改 CSS 就行了,動畫時間也須要再調試。(避嫌,具體結果不能提供 - -。)
譯者寫了一個 React + Hooks 的 UI 庫,方便你們學習和使用,
歡迎關注公衆號「前端進階課」認真學前端,一塊兒進階。