├── README.md
├── luckNine
├── index.css
└── index.jsx
├── luckRoll
├── index.css
└── index.jsx
└── luckTurn
├── index.css
└── index.jsx
/README.md:
--------------------------------------------------------------------------------
1 | # Lottery
2 | lottery game
3 |
4 | > React 抽奖,包含老虎机、转盘、九宫格三种形式。
5 | > 使用说明以及在线demo,点击下方链接。
6 |
7 | > demo :[https://blog.itakeo.com/luckGame/](https://blog.itakeo.com/luckGame/)
8 |
--------------------------------------------------------------------------------
/luckNine/index.css:
--------------------------------------------------------------------------------
1 | .luckNineBox{ position: relative;}
2 | .luckNineBox,.luckNineBox *{box-sizing: border-box;}
3 | .luckNineWrap{display:-webkit-flex;display:flex ;
4 | position: absolute;left: 0;top: 0;width: 100%;height: 100%;
5 | background: #ccc; flex-wrap: wrap;
6 | -webkit-flex-wrap: wrap;border-radius: 10px; overflow: hidden;
7 | }
8 | .luckNineWrap > *{
9 | -webkit-flex: 0 0 33.333333%;
10 | flex: 0 0 33.333333%;
11 | max-width: 33.333333%;
12 | height: 33.333333%; font-size: 24px;
13 | display:-webkit-flex;display:flex ;justify-content:center;-webkit-justify-content:center;align-items:center;-webkit-align-items:center
14 | }
15 | .luckNineWrap div{transition: all .05s ease;}
16 | .luckNineWrap div:first-of-type {
17 | background: #ccc
18 | }
19 |
20 | .luckNineWrap div:nth-of-type(2) {
21 | background: #c10
22 | }
23 |
24 | .luckNineWrap div:nth-of-type(3) {
25 | background: #1a0
26 | }
27 |
28 | .luckNineWrap div:nth-of-type(4) {
29 | background: #2e0
30 | }
31 |
32 | .luckNineWrap div:nth-of-type(5) {
33 | background: #cd9;
34 | text-align: center; cursor: pointer;
35 | }
36 |
37 | .luckNineWrap div:nth-of-type(6) {
38 | background: #ab3
39 | }
40 |
41 | .luckNineWrap div:nth-of-type(7) {
42 | background: #ef9
43 | }
44 |
45 | .luckNineWrap div:nth-of-type(8) {
46 | background: #c8c
47 | }
48 | .luckNineWrap div span{font-size: 26px; font-weight: bold;}
49 | .luckNineWrap div:nth-of-type(5):hover {
50 | background: #ffec0e;
51 | }
52 | .luckNineWrap div.active{
53 | background: #000; color: #fff;
54 | }
--------------------------------------------------------------------------------
/luckNine/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {forwardRef, useState, useRef,useEffect,useImperativeHandle } from 'react';
2 | import './index.css';
3 | let now = 0,
4 | count = 0,
5 | timer = null,
6 | speed = 50;
7 | const LuckNine = forwardRef((props,ref)=>{
8 | const [off , setOff] = useState(1); //防止重复点击开关
9 | useImperativeHandle(ref, () => ({
10 | start: (index,fn) => { //开始抽奖
11 | if(!off) return;
12 | setOff(0);
13 | changeFn(index,fn);
14 | },
15 | flag : off
16 | }));
17 | const changeFn = (index,fn)=>{
18 | let _item = document.querySelectorAll('.luckNineWrap .luckNineItem');
19 | now = ++now % (_item.length-1);
20 | now == 0 && count ++;
21 | _item.forEach(res=>{
22 | res.dataset.index == now ? res.classList.add('active') : res.classList.remove('active')
23 | });
24 | timer = setTimeout(()=>{
25 | changeFn(index,fn);
26 | },speed);
27 | if(count > 3) speed+=10;
28 | if(speed > 300 && now == index){
29 | clearTimeout(timer);
30 | count = 0;
31 | speed = 50;
32 | setOff(1);
33 | fn && fn(now)
34 | }
35 | }
36 |
37 |
38 | return (
39 |
40 |
41 |
1
42 |
2
43 |
3
44 |
8
45 |
{props.children}
46 |
4
47 |
7
48 |
6
49 |
5
50 |
51 |
52 | )
53 |
54 | })
55 |
56 | export default LuckNine;
--------------------------------------------------------------------------------
/luckRoll/index.css:
--------------------------------------------------------------------------------
1 | .luckRollBox{margin-bottom: 20px; position: relative; display:-webkit-flex;display:flex ; background: red; border-radius: 10px; padding: 10px;}
2 | .luckRollBox,.luckRollBox *{box-sizing: border-box;}
3 | .luckRollitem{
4 | flex: 1 1; height: 100%;overflow: hidden;
5 | background: #fff; border-radius: 6px;
6 | }
7 | .luckRollitem ul {
8 | height: 100%;
9 | transition: all .3s ease;
10 | }
11 | .luckRollitem li {
12 | list-style: none;
13 | width: 100%; line-height: 80px;
14 | height: 100%; font-size: 70px;
15 | text-align: center;
16 | position: relative;
17 | }
--------------------------------------------------------------------------------
/luckRoll/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {forwardRef, useState, useRef,useEffect,useImperativeHandle } from 'react';
2 | import './index.css';
3 |
4 | const LuckRoll = forwardRef((props,ref)=>{
5 | const [off , setOff] = useState(1); //防止重复点击开关
6 | const [liDom , setLiDom] = useState();
7 | const [rdmArr , setRdmArr] = useState([]);
8 | const rollRef = useRef();
9 | useImperativeHandle(ref, () => ({
10 | start: (arr,fn) => { //开始抽奖
11 | if(!off) return;
12 | setOff(0);
13 | let countNum = 0;
14 | rollRef.current.querySelectorAll('ul').forEach((res,index)=>{
15 | setTimeout(()=>{
16 | res.classList.add('luckRollActive')
17 | let _y = (arr[index] + props.list.length *5)*100;
18 | res.style['-webkit-transition'] = ` all ${props.time || 4000}ms ease`;
19 | res.style['-webkit-transform'] = `translate3d(0px, -${_y}%,0px)`;
20 | },index * 300);
21 | res.addEventListener('webkitTransitionEnd',(e)=>{
22 | res.classList.remove('luckRollActive')
23 | e.target.style['-webkit-transition'] = '0ms ease';
24 | e.target.style['-webkit-transform'] = `translate3d(0px, -${arr[index]*100}%,0px)`;
25 | countNum++;
26 | if(countNum == props.cols.length){
27 | setOff(1);
28 | fn && fn(arr);
29 | }
30 | },false);
31 | })
32 | },
33 | flag : off
34 | }));
35 |
36 | useEffect(()=>{
37 | let _li = new Array(6).fill('').map((res,index)=>{
38 | return (
39 | props.list.map((res2,index2)=>{
40 | return {index2}
41 | })
42 | )
43 | });
44 | setLiDom(_li);
45 | let _arr = [];
46 | new Array(props.cols*1).fill('').map((res,index)=>{
47 | _arr.push(Math.floor(Math.random() * props.list.length)*-100)
48 | });
49 | setRdmArr(_arr);
50 |
51 | },[]);
52 |
53 | return (
54 |
55 | {
56 | new Array(props.cols*1).fill('').map((res,index)=>{
57 | return (
58 |
61 | )
62 | })
63 | }
64 |
65 | )
66 |
67 | })
68 |
69 | export default React.memo(LuckRoll,()=>{
70 | return true
71 | });
--------------------------------------------------------------------------------
/luckTurn/index.css:
--------------------------------------------------------------------------------
1 | .luckTurnBox{ position: relative;display:-webkit-flex;display:flex ;justify-content:center;-webkit-justify-content:center;align-items:center;-webkit-align-items:center}
2 | .luckTurnBox,.luckTurnBox *{box-sizing: border-box;}
3 |
4 | .luckTurnBg{
5 | width: 100%;height: 100%;
6 | position: absolute; left: 0;top: 0;
7 | z-index: 10;
8 | }
9 | .luckTurnBtn{
10 | width: 50px;
11 | height: 50px;
12 | background: red;
13 | cursor: pointer;
14 | position: relative;
15 | z-index: 40;
16 | border-radius: 50%;
17 | color: #fff;
18 | border: none;
19 | outline: none;
20 | }
21 | .luckTurnBtn:after {
22 | content: "";
23 | display: block;
24 | width: 0;
25 | height: 0;
26 | border-color: transparent transparent red;
27 | border-style: solid;
28 | border-width: 0 10px 13px;
29 | position: absolute;
30 | left: 50%;
31 | top: -9px;
32 | margin-left: -10px;
33 | }
--------------------------------------------------------------------------------
/luckTurn/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {forwardRef, useState, useRef,useEffect,useImperativeHandle } from 'react';
2 | import './index.css';
3 | const LuckTurn = forwardRef((props,ref)=>{
4 | const [angle ,setAngle] = useState(0); //中奖角度
5 | const [off , setOff] = useState(1); //防止重复点击开关
6 | const [webkitTransform ,setWebkitTransform] = useState(''); //动画
7 | const [webkitTransition ,setWebkitTransition] = useState(''); //动画
8 | const didMountRef = useRef(false);
9 | const rotateRef = useRef(); //旋转DOM
10 | const cbRef = useRef(); //回调
11 |
12 | useImperativeHandle(ref, () => ({
13 | start: (val,fn) => { //开始抽奖
14 | if(!off) return;
15 | didMountRef.current = true;
16 | setOff(0);
17 | cbRef.current = fn || (()=>{});
18 | setAngle(360/props.size* val);
19 | setWebkitTransform(`rotateZ(${props.reset ? 0 : (360 - angle)}deg)`);
20 | setWebkitTransition( `-webkit-transform 0ms cubic-bezier(0.35, -0.005, 0.565, 1.005) 0s`)
21 | },
22 | flag : off
23 | }));
24 | const endFn = ()=>{
25 | setOff(1);
26 | rotateRef.current.removeEventListener('webkitTransitionEnd',endFn);
27 | cbRef.current();
28 | }
29 | useEffect(()=>{
30 | if(!didMountRef.current) return;
31 | didMountRef.current = false;
32 | setWebkitTransform(`rotateZ(${(3600 - angle)}deg)`);
33 | setWebkitTransition( `-webkit-transform ${props.time || 4000}ms cubic-bezier(0.35, -0.005, 0.565, 1.005) 0s`);
34 | rotateRef.current.addEventListener('webkitTransitionEnd',endFn);
35 | },[webkitTransform])
36 |
37 | return (
38 |
40 |
45 |
46 | {props.children}
47 |
48 | )
49 |
50 | })
51 |
52 | export default LuckTurn;
--------------------------------------------------------------------------------