最近工做中有個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宮格抽獎就完成了,有更好的,更豐富的方案的請不吝賜教。