最近在作一些h5活動的需求,發現用到轉盤的機會很大。react
代碼已經開源,感興趣的同窗可查看react-turnplategit
因而將轉盤組件化,具體的需求是:github
params | type | desc |
---|---|---|
image_spin | string | spin button |
background_1 | string | background_1 |
background_2 | string | background_2 |
prizeList | array | [{icon:'imageurl',name:'prize1',id:1},{icon:'imageurl',name:'prize1',id:2}] |
award | object | award should be null first,after request back return an object like prizelist[0] |
canStartRotate | bool | control the turnplate should startRotate |
onTryRotate | func | trigger after click the rotate button,should do some check stuff and if it's ok,set canStartRotate to be true then the turnplate start rotating,meanwhile request for the award and after the request finish,set the award |
rotateFinish | func |
這裏主要是兩張背景圖不斷替換,經過定時器,不斷替換background造成閃爍的效果.canvas
//外面閃閃發光的東東
_outDiscFlash() {
const { background_1, background_2 } = this.props;
this.outShowImg1 = !this.outShowImg1;
if (this.outShowImg1) {
this.refs.turnplateBorder.style.backgroundImage = `url(${background_1})`;
} else {
this.refs.turnplateBorder.style.backgroundImage = `url(${background_2})`;
}
this._flashTimer = setTimeout(this._outDiscFlash, this.outDiskDiffTimer);
}
_initFlash() {
const { background_1 } = this.props;
this.outDiskDiffTimer = 100;
this.outShowImg1 = true;
this._flashTimer = null;
this.refs.turnplateBorder.style.backgroundImage = `url(${background_1})`;
}
複製代碼
1.首先是根據傳進來的獎品數組個數,用canvas來畫扇形填充。用devicePixelRatio是爲了適配手機。數組
draw() {
const { prizeList } = this.props;
let rotateDeg = 360 / prizeList.length / 2 + 90, // 扇形迴轉角度
ctx;
const canvas = document.getElementById("canvas");
if (!canvas.getContext) {
return;
}
// 獲取繪圖上下文
ctx = canvas.getContext("2d");
for (let i = 0; i < prizeList.length; i++) {
// 保存當前狀態
ctx.save();
// 開始一條新路徑
ctx.beginPath();
// 位移到圓心,下面須要圍繞圓心旋轉
ctx.translate(105 * this.devicePixelRatio, 105 * this.devicePixelRatio);
// 從(0, 0)座標開始定義一條新的子路徑
ctx.moveTo(0, 0);
// 旋轉弧度,需將角度轉換爲弧度,使用 degrees * Math.PI/180 公式進行計算。
ctx.rotate((((360 / prizeList.length) * i - rotateDeg) * Math.PI) / 180);
// 繪製圓弧
ctx.arc(
0,
0,
105 * this.devicePixelRatio,
0,
(2 * Math.PI) / prizeList.length,
false
);
// 顏色間隔
if (i % 2 == 0) {
ctx.fillStyle = "#FFEAB0";
} else {
ctx.fillStyle = "#ffffff";
}
// 填充扇形
ctx.fill();
// 繪製邊框
ctx.lineWidth = 0.5;
ctx.strokeStyle = "#e4370e";
ctx.stroke();
// 恢復前一個狀態
ctx.restore();
}
}
複製代碼
2.其次是將產品填充,作一個rotate。bash
_getTurnPrizeList() {
const { prizeList } = this.props;
const turnplateList = [];
for (let i = 0; i < prizeList.length; i++) {
const turnplateItem = (
<li className="turnplate-item" key={i}>
<div style={{ transform: `rotate(${i / prizeList.length}turn)` }}>
<div>{prizeList[i].name}</div>
<img src={prizeList[i].icon} />
</div>
</li>
);
turnplateList.push(turnplateItem);
}
return <ul className="turnplate-list">{turnplateList}</ul>;
}
複製代碼
首先,可以在點擊轉的按鈕時候作一些判斷是否能夠開轉,使用變量canStartRotate來控制。當canStartRotate爲true後,一直旋轉,直到傳進來的award不爲空,每次transitionEnd判斷award的狀態,不爲空就結束旋轉,回調rotateFinish。app
UNSAFE_componentWillReceiveProps(nextProps, nextState) {
if (this.props.prizeList.length != nextProps.prizeList.length) {
this.draw();
}
//若是在請求,還沒返回結果,就先轉着
if (
!this.props.canStartRotate &&
nextProps.canStartRotate &&
!nextProps.award
) {
this._initFlash();
this._outDiscFlash();
this._justRotate();
}
if (!this.props.award && nextProps.award) {
this.setState({ award: nextProps.award });
}
}
_justRotate() {
const container = document.getElementById("turnplate");
const rotateDeg = 360 * 3;
this.setState({
lastRotateDeg: rotateDeg + this.state.lastRotateDeg,
rotating: true,
justRotate: true
});
container.style.transform =
"rotate(" + (rotateDeg + this.state.lastRotateDeg) + "deg)";
}
finishRotate() {
const { rotateFinish } = this.props;
const { award, justRotate } = this.state;
//若是獎品來了,而且不是justRotate
if (award && !justRotate) {
clearTimeout(this._flashTimer);
this.setState({ rotating: false });
rotateFinish(award);
}
//若是獎品來了,是justRotate,就開始抽
else if (award && justRotate) {
this._lottery();
} else {
//不然就繼續等吧兄弟
this._justRotate();
}
}
<div
className="turnplate-wrapper"
id="turnplate"
onTransitionEnd={this.finishRotate.bind(this)}
>
複製代碼
每次transition結束的時候都查看award是否已經傳入,可看到finishRotate有3種狀況的判斷組件化
這些以後都會在react-turnplate完善。ui
此處只是提供了一種思路,拋磚引玉。this