最近在作一些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