react 中使用九宫格抽奖
说明:因为大多数使用到的基本都是活动相关的,九宫格的对应的每个奖励也都是有中奖率的,具体的奖励都是后端返回的,所以我们在点击抽奖时一定会请求后端接口获取到返回的数据
1.首先,看jsx部分
return (
<ul styleName="list"> //这里我是用一个list去动态渲染他的奖励数据,当然,它的第五项是空的
{list.map((item, index) => {
if (index === 4) { //所以这边到了第五项的时候我只是把它的立即抽奖的图片放入了,然后加上了一个点击事件
return (
<li key={index}>
<img src={item.pic} alt="" onClick={handleClick} />
</li>
);
}
return ( //其他的则正常渲染
<li key={index}>
<img src={item.pic} alt="" />
{item.active ? <img src="" alt="" styleName="active" /> : null}
</li>
);
})}
</ul>
)
2.再看函数体部分
const initialActiveIndexRef = useRef(0);//这边是一个初始化
const resultRef = useRef({
result: null,
resultIndex: -1,
pending: false,
rolling: false,
error: null,
});
const INTERVAL = 125;//转盘的速度
const handleClick = useCallback(async () => {
const newInitialize = JSON.parse(JSON.stringify(Initialize));//不直接修改state,我这边是转化了一下
if (resultRef.current.rolling || resultRef.current.pending) {
return;
}//如果转盘在转或者按钮锁,则无法点击
if (newInitialize.value == 0) {
toast.show('您的抽奖次数不足');
return;
}//次数不足的话,直接不请求后端,前端拦截,减少请求
resultRef.current.pending = true;//开始后,把按钮锁和转盘锁打开
resultRef.current.rolling = true;
try {
const res = await hello(); //这里是await 请求结果
if (res.code == -1) { //如果请求出错的话,直接抛出了一个错误的小弹框
toast.show('错误');
resultRef.current.result = null; //并且把中奖数据设置为空,按钮锁设置为false,转盘设置为false
resultRef.current.pending = false;
resultRef.current.rolling = false;
return;
}
const resId = res.gift_id; //得到一个奖励的id
const resIndex = list.findIndex(i => i.gift_id == resId); //再用奖励id去找list内是否存在对应的奖励
if (resIndex < 0) { //如果不存在,则抛出错误的弹框
toast.show('未知错误');
resultRef.current.result = null;
resultRef.current.pending = false;
resultRef.current.rolling = false;
return;
} //否则,继续往下走
resultRef.current.result = res;//设置奖励信息
resultRef.current.resultIndex = resIndex; //设置对应的奖励下标
newInitialize.value -= 1;//再减去一次抽奖次数
setInitialize({
...newInitialize, //重新设置
});
} catch (err) {//如果请求出错,则catch出去
toast.show('数据请求出错,请重试');
resultRef.current.pending = false;
resultRef.current.rolling = false;
resultRef.current = null;
return;
}//否则,继续往下走
let currentIndex = initialActiveIndexRef.current;//设置一个默认的值
setList(
list.map((i, index) => {
return {
...i,
active: index === currentIndex,
};
}),
);
let loop = -1; //初始化
const timer = setInterval(() => { //开始转动
loop = currentIndex === initialActiveIndexRef.current ? loop + 1 : loop;//loop + num 与 转动的圈数有关
if (currentIndex < 2) {
currentIndex += 1;
} else if (currentIndex === 2 || currentIndex === 5) {
currentIndex += 3;
} else if (currentIndex === 3 || currentIndex === 6) {
currentIndex -= 3;
} else if (currentIndex > 6) {
currentIndex -= 1;
}
setList( //设置转动高亮状态
list.map((i, index) => {
return {
...i,
active: index === currentIndex,
};
}),
);
if (loop > 0) {
if (!resultRef.current.result || resultRef.current.resultIndex < 0) {//这边也是做的一个错误拦截
clearInterval(timer);
resultRef.current.rolling = false;
return;
}
if (currentIndex !== resultRef.current.resultIndex) {
return;
}
resultRef.current.rolling = false; //清楚转盘
clearInterval(timer);//清除延时器
initialActiveIndexRef.current = currentIndex;//转动完成后设置值
}
}, INTERVAL);//每一个格子停留的时间在外定义了
const timerOut = setTimeout(() => {
setIsShow(true);//我这边是写了一个小弹框展示
resultRef.current.pending = false;//这边我是让它在我弹框展示奖励后再取消按钮锁,否则,在等弹框展示奖励过程中再次抽奖,算是bug了
clearTimeout(timerOut);
}, 2200);
}, [list, Initialize]);//需要依赖一下抽奖的次数,和list
整个组件是一个函数式组件,所以有些地方之前用class组件的小伙伴如果不理解的话,可以看一下react官方文档的hooks部分哦
由于没有效果图,所以可能会有些奇奇怪怪,望大佬们见谅哈
本文章出自新手,轻喷
附上react官方链接,点击即可