UNPKG

lucky-wheel-component

Version:
92 lines (82 loc) 6.4 kB
'use strict'; var jsxRuntime = require('react/jsx-runtime'); var react = require('react'); function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = ".lucky-wheel {\r\n width: 100%;\r\n max-width: 600px;\r\n margin: 0 auto;\r\n}\r\n\r\n.wheel-box {\r\n width: 100%;\r\n padding-bottom: 100%;\r\n position: relative;\r\n}\r\n\r\n#wheel {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n border-radius: 50%;\r\n overflow: hidden;\r\n background: url('./assets/wheel-bg.png') center center no-repeat;\r\n background-size: 100% 100%;\r\n transform-origin: center center;\r\n transition: transform 5s cubic-bezier(0.46, 0.03, 0, 0.96);\r\n}\r\n\r\n/* 转盘内部样式 */\r\n.wheel-inner {\r\n position: absolute;\r\n width: 83%;\r\n height: 83%;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n border-radius: 50%;\r\n overflow: hidden;\r\n}\r\n\r\n.prize-part {\r\n height: 100%;\r\n width: 50%;\r\n position: absolute;\r\n top: 0;\r\n left: 50%;\r\n transform-origin: left center;\r\n box-sizing: border-box;\r\n}\r\n\r\n.prize-bg {\r\n width: 100%;\r\n height: 100%;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n}\r\n\r\n.prize-text {\r\n transform: translate(0, -50%) rotate(90deg);\r\n width: 100%;\r\n text-align: center;\r\n position: absolute;\r\n top: 50%;\r\n left: 20%;\r\n font-size: 1rem;\r\n padding-top: 0.3rem;\r\n box-sizing: border-box;\r\n white-space: nowrap;\r\n z-index: 1;\r\n}\r\n\r\n.pointer {\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 120px;\r\n height: 120px;\r\n background: url('./assets/game-arrow.png') center center no-repeat;\r\n background-size: contain;\r\n cursor: pointer;\r\n z-index: 2;\r\n}\r\n\r\n.pointer.disabled {\r\n cursor: not-allowed;\r\n opacity: 0.6;\r\n}\r\n\r\n/* 弹窗样式 */\r\n.modal {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n z-index: 1000;\r\n}\r\n\r\n.modal-content {\r\n background: white;\r\n padding: 20px;\r\n border-radius: 8px;\r\n position: relative;\r\n min-width: 300px;\r\n text-align: center;\r\n}\r\n\r\n.close {\r\n position: absolute;\r\n right: 10px;\r\n top: 5px;\r\n font-size: 24px;\r\n cursor: pointer;\r\n color: #666;\r\n}\r\n\r\n#modalMessage {\r\n margin: 20px 0;\r\n font-size: 16px;\r\n line-height: 1.5;\r\n white-space: pre-line;\r\n} "; styleInject(css_248z); const LuckyWheel = ({ prizes, initialDrawCount = 3, colors = ["#f31f49", "#fff7d7", "#a71d77"], textColors = ["#f3f1f1", "#a8213c", "#f3f1f1"], additionalTurns = 10, messages = { noChance: '您没有抽奖机会了' }, onStart, onComplete }) => { const [currentRotation, setCurrentRotation] = react.useState(0); const [isRotating, setIsRotating] = react.useState(false); const [drawCount, setDrawCount] = react.useState(initialDrawCount); const lastClickTime = react.useRef(0); const [lastRotation, setLastRotation] = react.useState(0); const wheelRef = react.useRef(null); const getPrizeStyle = react.useCallback((index) => { const perAngle = 360 / prizes.length; const p = perAngle / 2; const d = Math.tan(p * Math.PI / 180) * 100; const x = (100 - d) / 2; return { transform: `rotateZ(${perAngle / 2 - 90 + perAngle * index}deg)`, clipPath: `polygon(0% 50%, 100% ${x}%, 100% ${100 - x}%)` }; }, [prizes.length]); const startRotation = react.useCallback(() => { const now = Date.now(); if (now - lastClickTime.current < 1000 || isRotating || drawCount <= 0) { return; } lastClickTime.current = now; if (drawCount <= 0) { return; } setIsRotating(true); // 随机选择奖品 const prizeIndex = Math.floor(Math.random() * prizes.length); const perAngle = 360 / prizes.length; const targetAngle = prizeIndex * perAngle + perAngle / 2; // 计算旋转角度 const additionalRotation = 360 * additionalTurns; // 额外旋转10圈 const totalRotation = currentRotation - additionalRotation - targetAngle + lastRotation; // 应用旋转动画 if (wheelRef.current) { wheelRef.current.style.transform = `rotate(${totalRotation}deg)`; } // 触发开始事件 onStart?.({ prizeIndex, drawCount: drawCount - 1 }); // 动画结束后处理 setTimeout(() => { setDrawCount(prev => prev - 1); setIsRotating(false); setCurrentRotation(totalRotation); setLastRotation(targetAngle); const prize = prizes[prizeIndex]; onComplete?.({ index: prizeIndex, prize }); }, 5000); }, [currentRotation, drawCount, isRotating, prizes, onStart, onComplete, messages]); return (jsxRuntime.jsx("div", { className: "lucky-wheel", children: jsxRuntime.jsxs("div", { className: "wheel-box", children: [jsxRuntime.jsx("div", { id: "wheel", ref: wheelRef, children: jsxRuntime.jsx("div", { className: "wheel-inner", children: prizes.map((prize, index) => (jsxRuntime.jsxs("div", { className: "prize-part", style: getPrizeStyle(index), children: [jsxRuntime.jsx("div", { className: "prize-bg", style: { background: colors[index % colors.length] } }), jsxRuntime.jsx("div", { className: "prize-text", style: { color: textColors[index % textColors.length] }, children: prize.prize })] }, index))) }) }), jsxRuntime.jsx("div", { className: `pointer ${drawCount === 0 ? 'disabled' : ''}`, onClick: startRotation })] }) })); }; module.exports = LuckyWheel;