js實現(xiàn)抽獎功能

大致樣式如下:


一、構(gòu)思

獎勵物品是通過接口獲取的(img)

獎勵結(jié)果是通過接口獲取的(id)

抽獎的動畫需要由慢到快再到慢

抽獎轉(zhuǎn)動時間不能太短

抽獎結(jié)束需要回調(diào)

業(yè)務代碼和功能代碼要分離

二、先完成一個 UI

使用 flex 來布局,當?curGameIdx?等于當前獎品?index?時高亮

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>

css:

.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;

? ? ? ? ? ? }

? ? ? ? }

? ? }

效果圖:

三、開始做動畫效果

新建一個?Game?的?class,有有個?run?方法和?finish?方法

開始運行

動畫的速度是變化的,使用?requestAnimationFrame?和?setInterval?有點不妥,所以:可以使用?setTimeout?+?speed 參數(shù)?來控制動畫的速度。

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);

? ? }

}

結(jié)束運行

收到結(jié)束運行的通知時,需要先做減速動畫,然后再停止在對應的?num,然后調(diào)用回調(diào)函數(shù),所以先暫存結(jié)束回調(diào)和結(jié)束點,并將動畫設(shè)置為減速。

finish(num, finishCb) {

? ? ? ? this.oil = false;

? ? ? ? this.endIdx = num;

? ? ? ? this.finishCb = finishCb;

? ? }

速度的控制

1、默認速度為加速(this.oil = true)通過是否達到預期速度來停止加速,當減速時同理。

2、為達到緩動結(jié)束效果,所以結(jié)束時間通過:到達最小速度 且 到達結(jié)束位置。

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();

? ? ? ? ? ? }

? ? ? ? }

? ? }

index 矯正

此時,上面 UI 是通過?v-for?+?flex?展示的,而動畫的執(zhí)行是轉(zhuǎn)圈,所以需要矯正?index

更改上面?addIdx?方法,矯正 index,并將?++index?取余

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];

? ? }

活動代碼與業(yè)務代碼互動

將需要交互的函數(shù)傳遞給?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);

? ? }

? }

最后附上完整 Game 代碼:

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;

最后:樣式比較粗略,主要還是實現(xiàn)功能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,144評論 0 2
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,922評論 0 13
  • 講師五期分享673天 星期一 晴 2019.4.8 有付出就有收獲。建立單身群到現(xiàn)在一個多月的時間,也有了...
    追逐夢的自由閱讀 321評論 0 1
  • 今日學習內(nèi)容 1今天早上跟龐老師去做了50分鐘的沙盤。在這之前我覺的這因該是小孩子才玩的過家家游戲,但是我體驗后都...
    陳淑媚閱讀 60評論 0 0
  • 開始學習css的時候覺得這個屬性很簡單,就是一個單純的外邊距,和內(nèi)邊距padding是差不多內(nèi)容,只不過一個在內(nèi)部...
    離夢更近一點閱讀 394評論 0 0

友情鏈接更多精彩內(nèi)容