js 實現9宮格抽獎(react)

最近工做中有個9宮格抽獎的需求,一開始沒啥思緒,網上查閱一番,本身又修改了一下,但願與你們交流分享。css

先看一下效果圖 api

整理一下思路 利用flex佈局造成9宮格,每一個格子的序號爲0~8,建立一個記錄當前指針的變量,點擊抽獎,指正轉動,當index等於變量的時候讓當前格子與其餘格子樣式不一致,當請求後臺有結果時,讓指針等於結果值。數組

上圖中黑色數組表明獎品元素排列的順序,其中4爲抽獎按鈕,紅色數字則爲指針轉動的路線。bash

上代碼:async

首先定義幾個變量函數

constructor (props) {
    super(props)

    this.state = {
      timer1: '',         // 定時器1 快速旋轉
      timer2: '',         // 定時器2 慢速旋轉
      prizeIndex: 0,      // 轉動指針
      stopIndex: null,    // 抽中獎品
      arrNum: [0, 1, 2, 5, 8, 7, 6, 3],   // 轉動順序
      luckList: [],       // 獎品集合
      isRolling: false   // 是否正在抽獎
    }

    // 這邊綁定是必要的,這樣 `this` 才能在回調函數中使用
    this.drawPrize = this.drawPrize.bind(this);
    this.move = this.move.bind(this);
    this.lowSpeed = this.lowSpeed.bind(this);
  }
複製代碼

而後根據數據寫DOM渲染的條件佈局

由於後臺返回數據只有8條獎品,因此再獲取獎品集合時對數據作一些改變,這個根據實際狀況而定flex

res.data.dtls.splice(4, 0, {prizeName: "抽獎按鈕", type: 0});
複製代碼

這裏利用type屬性對獎品和抽獎按鈕作區分ui

renderLi = () => {
    let {luckList} = this.state;
    return luckList.map((list, index) => {
        if (list.type !== 0) {
            return <div key={index} className={list.chose === 1 ? 'chose box_prize' : 'box_prize'}>
                    {list.type===1||list.type===2?
                        <img alt="" src={require('./css/redpocket.png')}/> :
                      list.type===3?
                      <img alt="" src={require('./css/integral.png')}/> : ""
                    }
                    <div className="name">{list.prizeName}</div>
                  </div>
        } else {
            return <div key={index} className='box_prize click' onClick={this.drawPrize}></div>
        }

    })
  }
複製代碼
<div className="luck_turntable">
  {this.renderLi()}
</div>
複製代碼

點擊抽獎按鈕運行函數drawPrizethis

// 點擊抽獎 執行快速轉動,2秒後執行慢速轉動
  async drawPrize() {
    if (!this.state.isRolling) {
        this.setState({
            prizeIndex: 0,        
            stopIndex: null,
            isRolling: true,
            timer1: setInterval(this.move, 100)
        });
        setTimeout(() => {   //轉一圈半以後降速
            clearInterval(this.state.timer1); 
            this.lowSpeed()   
        }, 2000)
    }
}
複製代碼

慢速轉動

lowSpeed() {//慢速轉動
    // 先清除快速轉動的定時器
    clearInterval(this.state.timer1);
    
    // 請求接口,獲取轉動結果
    api.lotteryId(this.state.lotteryId, token).then(res => {
      if(res.resultCode === '0') {
        let stopIndex = null
        // 對轉動結果作處理
        switch (res.data) {
          case 4:
            stopIndex = 3
            break;
          case 7:
            stopIndex = 4
            break;
          case 6:
            stopIndex = 5
            break;
          case 5:
            stopIndex = 6
            break;
          case 3:
            stopIndex = 7
            break;
          case 0:
            stopIndex = 0
            break;
          case 1:
            stopIndex = 1
            break;
          case 2:
            stopIndex = 2
            break;
          default:
            stopIndex = null
            break
          }
        // 獲得結果再起調用move函數,速度下降
        this.setState({
          stopIndex: stopIndex,
          timer2: setInterval(this.move, 300)
        });
      }
  }
複製代碼

執行轉動函數move

move() {//轉動
    let luckList = this.state.luckList
    let arrNum = this.state.arrNum
    // chose=1爲轉動到位置,0爲正常位置
    luckList[arrNum[this.state.prizeIndex]].chose = 1
    luckList[arrNum[this.state.prizeIndex-1<0?7:this.state.prizeIndex-1]].chose = 0
    
    // 若是指針位置prizeIndex與結果位置相同,則抽獎完成,清除全部定時器
    if (this.state.stopIndex !== null && (this.state.prizeIndex === this.state.stopIndex)) {
      clearInterval(this.state.timer1);
      clearInterval(this.state.timer2);
      setTimeout(() => {
        this.setState({
            isRolling: false    // 能夠繼續抽獎
        })
      }, 300);
      
    } 
    // 不然,繼續轉動,這裏須要對零界位置作一下處理
    else {
      this.setState({
        prizeIndex: this.state.prizeIndex + 1 === 8 ? 0 : this.state.prizeIndex + 1
      })
    }
  }
複製代碼

另外須要在第二次點擊時恢復狀態值,我是在其餘條件下作的處理,這個根據實際狀況而定。

好了,一個簡單的9宮格抽獎就完成了,有更好的,更豐富的方案的請不吝賜教。

相關文章
相關標籤/搜索