├── 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 |
    59 | 60 |
    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; --------------------------------------------------------------------------------