文章目录
-
- 在当今互联网环境中,用户注意力已成为最稀缺的资源之一。网站运营者面临着一个共同的挑战:如何让访客停留更长时间,提高用户参与度,并最终实现转化率的提升?传统的内容展示方式已难以满足现代用户的需求,而互动元素的加入正成为解决这一问题的有效途径。 在线迷你游戏作为一种轻量级互动形式,具有以下优势: 提升用户停留时间:有趣的游戏体验能有效延长用户在网站的停留时间 增强品牌记忆:通过游戏化体验加深用户对品牌的印象 促进社交分享:用户乐于分享游戏成绩和体验,带来自然流量 收集用户数据:游戏过程中可以收集有价值的用户行为数据 提高转化率:游戏化元素可以作为引导用户完成特定动作的有效手段 本文将详细介绍如何通过WordPress代码二次开发,为你的网站添加实用的在线迷你游戏和小工具功能,从而显著提升用户互动与留存率。
-
- 在开始开发之前,确保你拥有以下环境: 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel WordPress安装:最新版本的WordPress(建议5.8以上) 代码编辑器:VS Code、Sublime Text或PHPStorm 浏览器开发者工具:用于调试JavaScript和CSS
- 为了避免主题更新导致自定义代码丢失,我们首先创建一个子主题: /* Theme Name: 我的游戏化子主题 Template: twentytwentythree Version: 1.0 Description: 为网站添加迷你游戏功能的子主题 */ // 引入父主题样式表 add_action('wp_enqueue_scripts', 'my_gamification_theme_enqueue_styles'); function my_gamification_theme_enqueue_styles() { wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css'); wp_enqueue_style('child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style')); }
- 在你的子主题目录中创建以下文件夹结构: /my-gamification-theme/ ├── games/ │ ├── js/ │ ├── css/ │ └── assets/ ├── includes/ ├── templates/ └── functions.php
-
- 记忆配对游戏是一种简单但有效的互动游戏,适合各种类型的网站。我们将实现以下功能: 可配置的卡片数量(4x4、4x5、5x6等) 计时器和步数计数器 得分系统 社交分享功能 保存最高分记录
- 在functions.php中添加短代码,使游戏可以轻松插入到任何文章或页面中: // 注册记忆游戏短代码 add_shortcode('memory_game', 'memory_game_shortcode'); function memory_game_shortcode($atts) { // 短代码属性 $atts = shortcode_atts( array( 'columns' => 4, 'rows' => 4, 'theme' => 'default' ), $atts, 'memory_game' ); // 生成唯一游戏ID $game_id = 'memory_game_' . uniqid(); // 输出游戏容器 ob_start(); ?> <div id="<?php echo esc_attr($game_id); ?>" class="memory-game-container" data-columns="<?php echo esc_attr($atts['columns']); ?>" data-rows="<?php echo esc_attr($atts['rows']); ?>" data-theme="<?php echo esc_attr($atts['theme']); ?>"> <div class="game-controls"> <div class="game-stats"> <span class="timer">时间: <span class="time-value">00:00</span></span> <span class="moves">步数: <span class="moves-value">0</span></span> <span class="score">得分: <span class="score-value">0</span></span> </div> <div class="game-buttons"> <button class="restart-game">重新开始</button> <button class="pause-game">暂停</button> </div> </div> <div class="game-board"></div> <div class="game-result" style="display:none;"> <h3>游戏结束!</h3> <p>你的得分: <span class="final-score">0</span></p> <p>用时: <span class="final-time">00:00</span></p> <p>步数: <span class="final-moves">0</span></p> <button class="play-again">再玩一次</button> <button class="share-score">分享成绩</button> </div> </div> <?php return ob_get_clean(); }
- 创建 /games/js/memory-game.js 文件: class MemoryGame { constructor(containerId) { this.container = document.getElementById(containerId); this.columns = parseInt(this.container.dataset.columns) || 4; this.rows = parseInt(this.container.dataset.rows) || 4; this.theme = this.container.dataset.theme || 'default'; this.totalPairs = (this.columns * this.rows) / 2; this.cards = []; this.flippedCards = []; this.matchedPairs = 0; this.moves = 0; this.score = 0; this.gameStarted = false; this.gamePaused = false; this.startTime = null; this.timerInterval = null; this.elapsedTime = 0; this.init(); } init() { this.createCards(); this.renderBoard(); this.setupEventListeners(); this.updateStats(); } createCards() { // 创建卡片对 const symbols = ['★', '❤', '♦', '♠', '♣', '☀', '☁', '☂', '☃', '♫', '⚓', '✈']; const usedSymbols = symbols.slice(0, this.totalPairs); // 每对卡片重复一次 let cardValues = [...usedSymbols, ...usedSymbols]; // 随机排序 cardValues = this.shuffleArray(cardValues); // 创建卡片对象 this.cards = cardValues.map((value, index) => ({ id: index, value: value, flipped: false, matched: false })); } shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } renderBoard() { const board = this.container.querySelector('.game-board'); board.innerHTML = ''; // 设置网格布局 board.style.gridTemplateColumns = `repeat(${this.columns}, 1fr)`; board.style.gridTemplateRows = `repeat(${this.rows}, 1fr)`; // 创建卡片元素 this.cards.forEach(card => { const cardElement = document.createElement('div'); cardElement.className = 'memory-card'; cardElement.dataset.id = card.id; const frontFace = document.createElement('div'); frontFace.className = 'card-front'; frontFace.textContent = card.value; const backFace = document.createElement('div'); backFace.className = 'card-back'; backFace.textContent = '?'; cardElement.appendChild(frontFace); cardElement.appendChild(backFace); board.appendChild(cardElement); }); } setupEventListeners() { // 卡片点击事件 this.container.addEventListener('click', (e) => { const cardElement = e.target.closest('.memory-card'); if (!cardElement || this.gamePaused) return; const cardId = parseInt(cardElement.dataset.id); this.flipCard(cardId); }); // 重新开始按钮 const restartBtn = this.container.querySelector('.restart-game'); restartBtn.addEventListener('click', () => this.restartGame()); // 暂停按钮 const pauseBtn = this.container.querySelector('.pause-game'); pauseBtn.addEventListener('click', () => this.togglePause()); // 再玩一次按钮 const playAgainBtn = this.container.querySelector('.play-again'); if (playAgainBtn) { playAgainBtn.addEventListener('click', () => this.restartGame()); } // 分享按钮 const shareBtn = this.container.querySelector('.share-score'); if (shareBtn) { shareBtn.addEventListener('click', () => this.shareScore()); } } flipCard(cardId) { // 如果游戏未开始,开始计时 if (!this.gameStarted) { this.startGame(); } const card = this.cards.find(c => c.id === cardId); // 如果卡片已匹配或已翻转,忽略点击 if (card.matched || card.flipped || this.flippedCards.length >= 2) { return; } // 翻转卡片 card.flipped = true; this.flippedCards.push(card); // 更新UI this.updateCardUI(cardId); // 如果翻转了两张卡片,检查是否匹配 if (this.flippedCards.length === 2) { this.moves++; this.updateStats(); const [card1, card2] = this.flippedCards; if (card1.value === card2.value) { // 匹配成功 card1.matched = true; card2.matched = true; this.matchedPairs++; this.score += 100; // 更新分数 this.updateStats(); // 清空翻转卡片数组 this.flippedCards = []; // 检查游戏是否结束 if (this.matchedPairs === this.totalPairs) { this.endGame(); } } else { // 不匹配,稍后翻转回来 setTimeout(() => { card1.flipped = false; card2.flipped = false; this.flippedCards = []; this.updateCardUI(card1.id); this.updateCardUI(card2.id); }, 1000); } } } updateCardUI(cardId) { const cardElement = this.container.querySelector(`[data-id="${cardId}"]`); const card = this.cards.find(c => c.id === cardId); if (card.flipped || card.matched) { cardElement.classList.add('flipped'); } else { cardElement.classList.remove('flipped'); } } startGame() { this.gameStarted = true; this.startTime = Date.now(); // 开始计时器 this.timerInterval = setInterval(() => { if (!this.gamePaused) { this.elapsedTime = Date.now() - this.startTime; this.updateStats(); } }, 1000); } togglePause() { this.gamePaused = !this.gamePaused; const pauseBtn = this.container.querySelector('.pause-game'); if (this.gamePaused) { pauseBtn.textContent = '继续'; } else { pauseBtn.textContent = '暂停'; // 如果游戏暂停后继续,调整开始时间 if (this.gameStarted) { this.startTime = Date.now() - this.elapsedTime; } } } updateStats() { // 更新时间显示 const timeElement = this.container.querySelector('.time-value'); const minutes = Math.floor(this.elapsedTime / 60000); const seconds = Math.floor((this.elapsedTime % 60000) / 1000); timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; // 更新步数 const movesElement = this.container.querySelector('.moves-value'); movesElement.textContent = this.moves; // 更新分数 const scoreElement = this.container.querySelector('.score-value'); scoreElement.textContent = this.score; } endGame() { clearInterval(this.timerInterval); // 计算最终得分(考虑时间和步数) const timeBonus = Math.max(0, 300 - Math.floor(this.elapsedTime / 1000)) * 10; const movesBonus = Math.max(0, 50 - this.moves) * 5; this.score += timeBonus + movesBonus; // 显示结果 const resultElement = this.container.querySelector('.game-result'); resultElement.querySelector('.final-score').textContent = this.score; resultElement.querySelector('.final-time').textContent = this.container.querySelector('.time-value').textContent; resultElement.querySelector('.final-moves').textContent = this.moves; resultElement.style.display = 'block'; // 保存最高分到本地存储 this.saveHighScore(); } saveHighScore() { const highScores = JSON.parse(localStorage.getItem('memoryGameHighScores') || '[]'); highScores.push({ score: this.score, time: this.elapsedTime, moves: this.moves, date: new Date().toISOString(), grid: `${this.columns}x${this.rows}` }); // 按分数排序,只保留前10名 highScores.sort((a, b) => b.score - a.score); const topScores = highScores.slice(0, 10); localStorage.setItem('memoryGameHighScores', JSON.stringify(topScores)); } shareScore() { const text = `我在记忆配对游戏中获得了${this.score}分!用时${this.container.querySelector('.time-value').textContent},用了${this.moves}步。`; if (navigator.share) { navigator.share({ title: '我的游戏成绩', text: text, url: window.location.href }); } else { // 备用方案:复制到剪贴板 navigator.clipboard.writeText(text).then(() => { alert('成绩已复制到剪贴板,快去分享吧!'); }); } } restartGame() { // 重置游戏状态 this.matchedPairs = 0; this.moves = 0; this.score = 0; this.gameStarted = false; this.gamePaused = false; this.flippedCards = []; this.elapsedTime = 0; clearInterval(this.timerInterval); // 重新创建卡片 this.createCards(); this.renderBoard(); // 隐藏结果 const resultElement = this.container.querySelector('.game-result'); resultElement.style.display = 'none'; // 更新统计 this.updateStats(); } } // 初始化所有记忆游戏实例 document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.memory-game-container').forEach(container => { new MemoryGame(container.id); }); });
- 创建 /games/css/memory-game.css 文件: .memory-game-container { max-width: 800px; margin: 20px auto; padding: 20px; background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); border-radius: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); color: white; font-family: 'Arial', sans-serif; } .game-controls { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding: 15px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; flex-wrap: wrap; } .game-stats { display: flex; gap: 20px; font-size: 18px; font-weight: bold; } .game-stats span { background: rgba(0, 0, 0, 0.2); padding: 8px 15px; border-radius: 5px; } .game-buttons { display: flex; gap: 10px; } .game-buttons button { padding: 10px 20px; border: none; border-radius: 5px; background: #4CAF50; color: white; font-weight: bold; cursor: pointer; transition: all 0.3s ease; } .game-buttons button:hover { background: #45a049; transform: translateY(-2px); } .game-buttons .pause-game { background: #ff9800; } .game-buttons .pause-game:hover { background: #e68900; } .game-board { display: grid; gap: 10px; margin: 20px 0; perspective: 1000px; } .memory-card { height: 100px; position: relative; transform-style: preserve-3d; transition: transform 0.6s; cursor: pointer; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } .memory-card.flipped { transform: rotateY(180deg); } .memory-card .card-front, .memory-card .card-back { position: absolute; width: 100%; height: 100%; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 2em; font-weight: bold; } .memory-card .card-back { background: linear-gradient(45deg, #2196F3, #21CBF3); color: white; transform: rotateY(0deg); } .memory-card .card-front { background: linear-gradient(45deg, #FF9800, #FFC107); color: white; transform: rotateY(180deg); } .memory-card.matched .card-front { background: linear-gradient(45deg, #4CAF50, #8BC34A); } .game-result { text-align: center; padding: 30px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; margin-top: 20px; animation: fadeIn 0.5s ease; } .game-result h3 { font-size: 28px; margin-bottom: 20px; color: #FFEB3B; } .game-result p { font-size: 18px; margin: 10px 0; } .game-result button { margin: 10px; padding: 12px 25px; border: none; border-radius: 5px; font-size: 16px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; } .game-result .play-again { background: #4CAF50; color: white; } .game-result .share-score { background: #2196F3; color: white; } .game-result button:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* 响应式设计 */ @media (max-width: 768px) { .game-controls { flex-direction: column; gap: 15px; } .game-stats { flex-wrap: wrap; justify-content: center; } .memory-card { height: 80px; } } @media (max-width: 480px) { .memory-card { height: 60px; } .memory-card .card-front, .memory-card .card-back { font-size: 1.5em; } }
- 在functions.php中添加以下代码,确保游戏脚本和样式正确加载: // 注册并加载记忆游戏资源 add_action('wp_enqueue_scripts', 'register_memory_game_assets'); function register_memory_game_assets() { // 只在需要时加载游戏资源 global $post; if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'memory_game')) { // 游戏样式 wp_enqueue_style( 'memory-game-css', get_stylesheet_directory_uri() . '/games/css/memory-game.css', array(), '1.0.0' ); // 游戏脚本 wp_enqueue_script( 'memory-game-js', get_stylesheet_directory_uri() . '/games/js/memory-game.js', array(), '1.0.0', true ); } }
-
- 抽奖转盘是另一种受欢迎的互动形式,特别适合电商网站和营销活动。我们将创建一个可配置的转盘游戏: // 注册转盘游戏短代码 add_shortcode('wheel_of_fortune', 'wheel_of_fortune_shortcode'); function wheel_of_fortune_shortcode($atts) { $atts = shortcode_atts( array( 'segments' => '优惠券10%,谢谢参与,优惠券20%,再来一次,折扣30%,幸运奖,优惠券15%,大奖', 'colors' => '#FF6384,#36A2EB,#FFCE56,#4BC0C0,#9966FF,#FF9F40,#FF6384,#36A2EB', 'prize_text' => '恭喜您获得:', 'button_text' => '开始抽奖' ), $atts, 'wheel_of_fortune' ); $game_id = 'wheel_game_' . uniqid(); $segments = explode(',', $atts['segments']); $colors = explode(',', $atts['colors']); ob_start(); ?> <div id="<?php echo esc_attr($game_id); ?>" class="wheel-game-container"> <div class="wheel-header"> <h3>幸运大转盘</h3> <p>试试你的运气,赢取惊喜奖励!</p> </div> <div class="wheel-content"> <div class="wheel-wrapper"> <canvas id="<?php echo esc_attr($game_id); ?>_canvas" class="wheel-canvas" width="400" height="400"></canvas> <div class="wheel-pointer"></div> </div> <div class="wheel-controls"> <div class="wheel-stats"> <p>剩余抽奖次数: <span class="spins-left">3</span></p> <p class="prize-result"></p> </div> <button class="spin-button"><?php echo esc_html($atts['button_text']); ?></button> <button class="reset-spins">重置次数</button> <div class="wheel-segments"> <h4>奖项设置:</h4> <ul> <?php foreach ($segments as $index => $segment): ?> <li> <span class="segment-color" style="background-color: <?php echo esc_attr($colors[$index % count($colors)]); ?>"></span> <?php echo esc_html($segment); ?> </li> <?php endforeach; ?> </ul> </div> </div> </div> <div class="wheel-history"> <h4>中奖记录</h4> <ul class="history-list"></ul> </div> </div> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { new WheelOfFortune( '<?php echo esc_js($game_id); ?>', <?php echo json_encode($segments); ?>, <?php echo json_encode($colors); ?>, '<?php echo esc_js($atts['prize_text']); ?>' ); }); </script> <?php return ob_get_clean(); }
- 创建 /games/js/wheel-game.js 文件: class WheelOfFortune { constructor(containerId, segments, colors, prizeText) { this.container = document.getElementById(containerId); this.canvas = this.container.querySelector('.wheel-canvas'); this.ctx = this.canvas.getContext('2d'); this.spinButton = this.container.querySelector('.spin-button'); this.resetButton = this.container.querySelector('.reset-spins'); this.prizeResult = this.container.querySelector('.prize-result'); this.spinsLeftElement = this.container.querySelector('.spins-left'); this.historyList = this.container.querySelector('.history-list'); this.segments = segments; this.colors = colors; this.prizeText = prizeText; // 游戏状态 this.spinsLeft = 3; this.isSpinning = false; this.currentRotation = 0; this.segmentAngle = (2 * Math.PI) / this.segments.length; this.init(); } init() { this.drawWheel(); this.setupEventListeners(); this.updateSpinsDisplay(); this.loadHistory(); } drawWheel() { const centerX = this.canvas.width / 2; const centerY = this.canvas.height / 2; const radius = Math.min(centerX, centerY) - 10; // 清除画布 this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // 绘制每个扇形 for (let i = 0; i < this.segments.length; i++) { const startAngle = this.currentRotation + (i * this.segmentAngle); const endAngle = startAngle + this.segmentAngle; // 绘制扇形 this.ctx.beginPath(); this.ctx.moveTo(centerX, centerY); this.ctx.arc(centerX, centerY, radius, startAngle, endAngle); this.ctx.closePath(); // 填充颜色 this.ctx.fillStyle = this.colors[i % this.colors.length]; this.ctx.fill(); // 绘制边框 this.ctx.strokeStyle = '#FFFFFF'; this.ctx.lineWidth = 2; this.ctx.stroke(); // 绘制文本 this.ctx.save(); this.ctx.translate(centerX, centerY); this.ctx.rotate(startAngle + this.segmentAngle / 2); this.ctx.textAlign = 'right'; this.ctx.fillStyle = '#FFFFFF'; this.ctx.font = 'bold 14px Arial'; this.ctx.fillText(this.segments[i], radius - 20, 5); this.ctx.restore(); } // 绘制中心圆 this.ctx.beginPath(); this.ctx.arc(centerX, centerY, 20, 0, 2 * Math.PI); this.ctx.fillStyle = '#333333'; this.ctx.fill(); this.ctx.strokeStyle = '#FFFFFF'; this.ctx.lineWidth = 3; this.ctx.stroke(); } setupEventListeners() { this.spinButton.addEventListener('click', () => this.spinWheel()); this.resetButton.addEventListener('click', () => this.resetSpins()); } spinWheel() { if (this.isSpinning || this.spinsLeft <= 0) return; this.isSpinning = true; this.spinsLeft--; this.updateSpinsDisplay(); // 随机决定停止位置 const spinDuration = 3000 + Math.random() * 2000; // 3-5秒 const extraRotation = 5 + Math.random() * 5; // 额外旋转5-10圈 const totalRotation = (extraRotation * 2 * Math.PI) + (Math.random() * this.segmentAngle); // 动画开始时间 const startTime = Date.now(); const animate = () => { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / spinDuration, 1); // 缓动函数:先快后慢 const easeOut = 1 - Math.pow(1 - progress, 3); // 更新旋转角度 this.currentRotation = easeOut * totalRotation; this.drawWheel(); if (progress < 1) { requestAnimationFrame(animate); } else { // 动画结束 this.isSpinning = false; this.determinePrize(); } }; animate(); } determinePrize() { // 计算指针指向的扇形 const normalizedRotation = this.currentRotation % (2 * Math.PI); const segmentIndex = Math.floor( ((2 * Math.PI - normalizedRotation) % (2 * Math.PI)) / this.segmentAngle ); const prize = this.segments[segmentIndex]; // 显示结果 this.prizeResult.textContent = `${this.prizeText} ${prize}`; this.prizeResult.style.color = this.colors[segmentIndex % this.colors.length]; // 添加到历史记录 this.addToHistory(prize); // 保存到本地存储 this.saveHistory(prize); // 如果是"再来一次",增加一次抽奖机会 if (prize === '再来一次') { this.spinsLeft++; this.updateSpinsDisplay(); } } addToHistory(prize) { const now = new Date(); const timeString = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); const historyItem = document.createElement('li'); historyItem.innerHTML = ` <span class="history-time">${timeString}</span> <span class="history-prize">${prize}</span> `; this.historyList.insertBefore(historyItem, this.historyList.firstChild); // 限制历史记录数量 if (this.historyList.children.length > 10) { this.historyList.removeChild(this.historyList.lastChild); } } saveHistory(prize) { const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]'); history.unshift({ prize: prize, timestamp: new Date().toISOString() }); // 只保留最近20条记录 const recentHistory = history.slice(0, 20); localStorage.setItem('wheelGameHistory', JSON.stringify(recentHistory)); } loadHistory() { const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]'); history.forEach(item => { const date = new Date(item.timestamp); const timeString = date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); const historyItem = document.createElement('li'); historyItem.innerHTML = ` <span class="history-time">${timeString}</span> <span class="history-prize">${item.prize}</span> `; this.historyList.appendChild(historyItem); }); } updateSpinsDisplay() { this.spinsLeftElement.textContent = this.spinsLeft; if (this.spinsLeft <= 0) { this.spinButton.disabled = true; this.spinButton.textContent = '次数已用完'; } else { this.spinButton.disabled = false; this.spinButton.textContent = '开始抽奖'; } } resetSpins() { this.spinsLeft = 3; this.updateSpinsDisplay(); this.prizeResult.textContent = ''; } }
- 创建 /games/css/wheel-game.css 文件: .wheel-game-container { max-width: 900px; margin: 30px auto; padding: 25px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2); color: white; font-family: 'Arial', sans-serif; } .wheel-header { text-align: center; margin-bottom: 30px; } .wheel-header h3 { font-size: 32px; margin-bottom: 10px; color: #FFD700; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); } .wheel-header p { font-size: 18px; opacity: 0.9; } .wheel-content { display: flex; flex-wrap: wrap; gap: 40px; align-items: center; justify-content: center; } .wheel-wrapper { position: relative; flex: 0 0 auto; } .wheel-canvas { background: white; border-radius: 50%; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); border: 8px solid #FFD700; } .wheel-pointer { position: absolute; top: -20px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 20px solid transparent; border-right: 20px solid transparent; border-top: 40px solid #FF0000; filter: drop-shadow(0 5px 5px rgba(0, 0, 0, 0.3)); z-index: 10; } .wheel-controls { flex: 1; min-width: 300px; background: rgba(255, 255, 255, 0.1); padding: 25px; border-radius: 15px; backdrop-filter: blur(10px); } .wheel-stats { margin-bottom: 25px; padding: 15px; background: rgba(0, 0, 0, 0.2); border-radius: 10px; } .wheel-stats p { font-size: 18px; margin: 10px 0; } .prize-result { font-size: 22px !important; font-weight: bold; color: #FFD700 !important; min-height: 30px; margin-top: 15px !important; } .wheel-controls button { display: block; width: 100%; padding: 15px; margin: 10px 0; border: none; border-radius: 8px; font-size: 18px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; } .spin-button { background: linear-gradient(45deg, #FF416C, #FF4B2B); color: white; } .spin-button:hover:not(:disabled) { transform: translateY(-3px);
在当今互联网环境中,用户注意力已成为最稀缺的资源之一。网站运营者面临着一个共同的挑战:如何让访客停留更长时间,提高用户参与度,并最终实现转化率的提升?传统的内容展示方式已难以满足现代用户的需求,而互动元素的加入正成为解决这一问题的有效途径。
在线迷你游戏作为一种轻量级互动形式,具有以下优势:
- 提升用户停留时间:有趣的游戏体验能有效延长用户在网站的停留时间
- 增强品牌记忆:通过游戏化体验加深用户对品牌的印象
- 促进社交分享:用户乐于分享游戏成绩和体验,带来自然流量
- 收集用户数据:游戏过程中可以收集有价值的用户行为数据
- 提高转化率:游戏化元素可以作为引导用户完成特定动作的有效手段
本文将详细介绍如何通过WordPress代码二次开发,为你的网站添加实用的在线迷你游戏和小工具功能,从而显著提升用户互动与留存率。
在开始开发之前,确保你拥有以下环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:最新版本的WordPress(建议5.8以上)
- 代码编辑器:VS Code、Sublime Text或PHPStorm
- 浏览器开发者工具:用于调试JavaScript和CSS
为了避免主题更新导致自定义代码丢失,我们首先创建一个子主题:
/*
Theme Name: 我的游戏化子主题
Template: twentytwentythree
Version: 1.0
Description: 为网站添加迷你游戏功能的子主题
*/
// 引入父主题样式表
add_action('wp_enqueue_scripts', 'my_gamification_theme_enqueue_styles');
function my_gamification_theme_enqueue_styles() {
wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
wp_enqueue_style('child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}
在你的子主题目录中创建以下文件夹结构:
/my-gamification-theme/
├── games/
│ ├── js/
│ ├── css/
│ └── assets/
├── includes/
├── templates/
└── functions.php
记忆配对游戏是一种简单但有效的互动游戏,适合各种类型的网站。我们将实现以下功能:
- 可配置的卡片数量(4x4、4x5、5x6等)
- 计时器和步数计数器
- 得分系统
- 社交分享功能
- 保存最高分记录
在functions.php中添加短代码,使游戏可以轻松插入到任何文章或页面中:
// 注册记忆游戏短代码
add_shortcode('memory_game', 'memory_game_shortcode');
function memory_game_shortcode($atts) {
// 短代码属性
$atts = shortcode_atts(
array(
'columns' => 4,
'rows' => 4,
'theme' => 'default'
),
$atts,
'memory_game'
);
// 生成唯一游戏ID
$game_id = 'memory_game_' . uniqid();
// 输出游戏容器
ob_start();
?>
<div id="<?php echo esc_attr($game_id); ?>" class="memory-game-container"
data-columns="<?php echo esc_attr($atts['columns']); ?>"
data-rows="<?php echo esc_attr($atts['rows']); ?>"
data-theme="<?php echo esc_attr($atts['theme']); ?>">
<div class="game-controls">
<div class="game-stats">
<span class="timer">时间: <span class="time-value">00:00</span></span>
<span class="moves">步数: <span class="moves-value">0</span></span>
<span class="score">得分: <span class="score-value">0</span></span>
</div>
<div class="game-buttons">
<button class="restart-game">重新开始</button>
<button class="pause-game">暂停</button>
</div>
</div>
<div class="game-board"></div>
<div class="game-result" style="display:none;">
<h3>游戏结束!</h3>
<p>你的得分: <span class="final-score">0</span></p>
<p>用时: <span class="final-time">00:00</span></p>
<p>步数: <span class="final-moves">0</span></p>
<button class="play-again">再玩一次</button>
<button class="share-score">分享成绩</button>
</div>
</div>
<?php
return ob_get_clean();
}
创建 /games/js/memory-game.js 文件:
class MemoryGame {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.columns = parseInt(this.container.dataset.columns) || 4;
this.rows = parseInt(this.container.dataset.rows) || 4;
this.theme = this.container.dataset.theme || 'default';
this.totalPairs = (this.columns * this.rows) / 2;
this.cards = [];
this.flippedCards = [];
this.matchedPairs = 0;
this.moves = 0;
this.score = 0;
this.gameStarted = false;
this.gamePaused = false;
this.startTime = null;
this.timerInterval = null;
this.elapsedTime = 0;
this.init();
}
init() {
this.createCards();
this.renderBoard();
this.setupEventListeners();
this.updateStats();
}
createCards() {
// 创建卡片对
const symbols = ['★', '❤', '♦', '♠', '♣', '☀', '☁', '☂', '☃', '♫', '⚓', '✈'];
const usedSymbols = symbols.slice(0, this.totalPairs);
// 每对卡片重复一次
let cardValues = [...usedSymbols, ...usedSymbols];
// 随机排序
cardValues = this.shuffleArray(cardValues);
// 创建卡片对象
this.cards = cardValues.map((value, index) => ({
id: index,
value: value,
flipped: false,
matched: false
}));
}
shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
renderBoard() {
const board = this.container.querySelector('.game-board');
board.innerHTML = '';
// 设置网格布局
board.style.gridTemplateColumns = `repeat(${this.columns}, 1fr)`;
board.style.gridTemplateRows = `repeat(${this.rows}, 1fr)`;
// 创建卡片元素
this.cards.forEach(card => {
const cardElement = document.createElement('div');
cardElement.className = 'memory-card';
cardElement.dataset.id = card.id;
const frontFace = document.createElement('div');
frontFace.className = 'card-front';
frontFace.textContent = card.value;
const backFace = document.createElement('div');
backFace.className = 'card-back';
backFace.textContent = '?';
cardElement.appendChild(frontFace);
cardElement.appendChild(backFace);
board.appendChild(cardElement);
});
}
setupEventListeners() {
// 卡片点击事件
this.container.addEventListener('click', (e) => {
const cardElement = e.target.closest('.memory-card');
if (!cardElement || this.gamePaused) return;
const cardId = parseInt(cardElement.dataset.id);
this.flipCard(cardId);
});
// 重新开始按钮
const restartBtn = this.container.querySelector('.restart-game');
restartBtn.addEventListener('click', () => this.restartGame());
// 暂停按钮
const pauseBtn = this.container.querySelector('.pause-game');
pauseBtn.addEventListener('click', () => this.togglePause());
// 再玩一次按钮
const playAgainBtn = this.container.querySelector('.play-again');
if (playAgainBtn) {
playAgainBtn.addEventListener('click', () => this.restartGame());
}
// 分享按钮
const shareBtn = this.container.querySelector('.share-score');
if (shareBtn) {
shareBtn.addEventListener('click', () => this.shareScore());
}
}
flipCard(cardId) {
// 如果游戏未开始,开始计时
if (!this.gameStarted) {
this.startGame();
}
const card = this.cards.find(c => c.id === cardId);
// 如果卡片已匹配或已翻转,忽略点击
if (card.matched || card.flipped || this.flippedCards.length >= 2) {
return;
}
// 翻转卡片
card.flipped = true;
this.flippedCards.push(card);
// 更新UI
this.updateCardUI(cardId);
// 如果翻转了两张卡片,检查是否匹配
if (this.flippedCards.length === 2) {
this.moves++;
this.updateStats();
const [card1, card2] = this.flippedCards;
if (card1.value === card2.value) {
// 匹配成功
card1.matched = true;
card2.matched = true;
this.matchedPairs++;
this.score += 100;
// 更新分数
this.updateStats();
// 清空翻转卡片数组
this.flippedCards = [];
// 检查游戏是否结束
if (this.matchedPairs === this.totalPairs) {
this.endGame();
}
} else {
// 不匹配,稍后翻转回来
setTimeout(() => {
card1.flipped = false;
card2.flipped = false;
this.flippedCards = [];
this.updateCardUI(card1.id);
this.updateCardUI(card2.id);
}, 1000);
}
}
}
updateCardUI(cardId) {
const cardElement = this.container.querySelector(`[data-id="${cardId}"]`);
const card = this.cards.find(c => c.id === cardId);
if (card.flipped || card.matched) {
cardElement.classList.add('flipped');
} else {
cardElement.classList.remove('flipped');
}
}
startGame() {
this.gameStarted = true;
this.startTime = Date.now();
// 开始计时器
this.timerInterval = setInterval(() => {
if (!this.gamePaused) {
this.elapsedTime = Date.now() - this.startTime;
this.updateStats();
}
}, 1000);
}
togglePause() {
this.gamePaused = !this.gamePaused;
const pauseBtn = this.container.querySelector('.pause-game');
if (this.gamePaused) {
pauseBtn.textContent = '继续';
} else {
pauseBtn.textContent = '暂停';
// 如果游戏暂停后继续,调整开始时间
if (this.gameStarted) {
this.startTime = Date.now() - this.elapsedTime;
}
}
}
updateStats() {
// 更新时间显示
const timeElement = this.container.querySelector('.time-value');
const minutes = Math.floor(this.elapsedTime / 60000);
const seconds = Math.floor((this.elapsedTime % 60000) / 1000);
timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
// 更新步数
const movesElement = this.container.querySelector('.moves-value');
movesElement.textContent = this.moves;
// 更新分数
const scoreElement = this.container.querySelector('.score-value');
scoreElement.textContent = this.score;
}
endGame() {
clearInterval(this.timerInterval);
// 计算最终得分(考虑时间和步数)
const timeBonus = Math.max(0, 300 - Math.floor(this.elapsedTime / 1000)) * 10;
const movesBonus = Math.max(0, 50 - this.moves) * 5;
this.score += timeBonus + movesBonus;
// 显示结果
const resultElement = this.container.querySelector('.game-result');
resultElement.querySelector('.final-score').textContent = this.score;
resultElement.querySelector('.final-time').textContent =
this.container.querySelector('.time-value').textContent;
resultElement.querySelector('.final-moves').textContent = this.moves;
resultElement.style.display = 'block';
// 保存最高分到本地存储
this.saveHighScore();
}
saveHighScore() {
const highScores = JSON.parse(localStorage.getItem('memoryGameHighScores') || '[]');
highScores.push({
score: this.score,
time: this.elapsedTime,
moves: this.moves,
date: new Date().toISOString(),
grid: `${this.columns}x${this.rows}`
});
// 按分数排序,只保留前10名
highScores.sort((a, b) => b.score - a.score);
const topScores = highScores.slice(0, 10);
localStorage.setItem('memoryGameHighScores', JSON.stringify(topScores));
}
shareScore() {
const text = `我在记忆配对游戏中获得了${this.score}分!用时${this.container.querySelector('.time-value').textContent},用了${this.moves}步。`;
if (navigator.share) {
navigator.share({
title: '我的游戏成绩',
text: text,
url: window.location.href
});
} else {
// 备用方案:复制到剪贴板
navigator.clipboard.writeText(text).then(() => {
alert('成绩已复制到剪贴板,快去分享吧!');
});
}
}
restartGame() {
// 重置游戏状态
this.matchedPairs = 0;
this.moves = 0;
this.score = 0;
this.gameStarted = false;
this.gamePaused = false;
this.flippedCards = [];
this.elapsedTime = 0;
clearInterval(this.timerInterval);
// 重新创建卡片
this.createCards();
this.renderBoard();
// 隐藏结果
const resultElement = this.container.querySelector('.game-result');
resultElement.style.display = 'none';
// 更新统计
this.updateStats();
}
}
// 初始化所有记忆游戏实例
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.memory-game-container').forEach(container => {
new MemoryGame(container.id);
});
});
创建 /games/css/memory-game.css 文件:
.memory-game-container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
color: white;
font-family: 'Arial', sans-serif;
}
.game-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
flex-wrap: wrap;
}
.game-stats {
display: flex;
gap: 20px;
font-size: 18px;
font-weight: bold;
}
.game-stats span {
background: rgba(0, 0, 0, 0.2);
padding: 8px 15px;
border-radius: 5px;
}
.game-buttons {
display: flex;
gap: 10px;
}
.game-buttons button {
padding: 10px 20px;
border: none;
border-radius: 5px;
background: #4CAF50;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.game-buttons button:hover {
background: #45a049;
transform: translateY(-2px);
}
.game-buttons .pause-game {
background: #ff9800;
}
.game-buttons .pause-game:hover {
background: #e68900;
}
.game-board {
display: grid;
gap: 10px;
margin: 20px 0;
perspective: 1000px;
}
.memory-card {
height: 100px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
cursor: pointer;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.memory-card.flipped {
transform: rotateY(180deg);
}
.memory-card .card-front,
.memory-card .card-back {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2em;
font-weight: bold;
}
.memory-card .card-back {
background: linear-gradient(45deg, #2196F3, #21CBF3);
color: white;
transform: rotateY(0deg);
}
.memory-card .card-front {
background: linear-gradient(45deg, #FF9800, #FFC107);
color: white;
transform: rotateY(180deg);
}
.memory-card.matched .card-front {
background: linear-gradient(45deg, #4CAF50, #8BC34A);
}
.game-result {
text-align: center;
padding: 30px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
margin-top: 20px;
animation: fadeIn 0.5s ease;
}
.game-result h3 {
font-size: 28px;
margin-bottom: 20px;
color: #FFEB3B;
}
.game-result p {
font-size: 18px;
margin: 10px 0;
}
.game-result button {
margin: 10px;
padding: 12px 25px;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.game-result .play-again {
background: #4CAF50;
color: white;
}
.game-result .share-score {
background: #2196F3;
color: white;
}
.game-result button:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* 响应式设计 */
@media (max-width: 768px) {
.game-controls {
flex-direction: column;
gap: 15px;
}
.game-stats {
flex-wrap: wrap;
justify-content: center;
}
.memory-card {
height: 80px;
}
}
@media (max-width: 480px) {
.memory-card {
height: 60px;
}
.memory-card .card-front,
.memory-card .card-back {
font-size: 1.5em;
}
}
在functions.php中添加以下代码,确保游戏脚本和样式正确加载:
// 注册并加载记忆游戏资源
add_action('wp_enqueue_scripts', 'register_memory_game_assets');
function register_memory_game_assets() {
// 只在需要时加载游戏资源
global $post;
if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'memory_game')) {
// 游戏样式
wp_enqueue_style(
'memory-game-css',
get_stylesheet_directory_uri() . '/games/css/memory-game.css',
array(),
'1.0.0'
);
// 游戏脚本
wp_enqueue_script(
'memory-game-js',
get_stylesheet_directory_uri() . '/games/js/memory-game.js',
array(),
'1.0.0',
true
);
}
}
抽奖转盘是另一种受欢迎的互动形式,特别适合电商网站和营销活动。我们将创建一个可配置的转盘游戏:
// 注册转盘游戏短代码
add_shortcode('wheel_of_fortune', 'wheel_of_fortune_shortcode');
function wheel_of_fortune_shortcode($atts) {
$atts = shortcode_atts(
array(
'segments' => '优惠券10%,谢谢参与,优惠券20%,再来一次,折扣30%,幸运奖,优惠券15%,大奖',
'colors' => '#FF6384,#36A2EB,#FFCE56,#4BC0C0,#9966FF,#FF9F40,#FF6384,#36A2EB',
'prize_text' => '恭喜您获得:',
'button_text' => '开始抽奖'
),
$atts,
'wheel_of_fortune'
);
$game_id = 'wheel_game_' . uniqid();
$segments = explode(',', $atts['segments']);
$colors = explode(',', $atts['colors']);
ob_start();
?>
<div id="<?php echo esc_attr($game_id); ?>" class="wheel-game-container">
<div class="wheel-header">
<h3>幸运大转盘</h3>
<p>试试你的运气,赢取惊喜奖励!</p>
</div>
<div class="wheel-content">
<div class="wheel-wrapper">
<canvas id="<?php echo esc_attr($game_id); ?>_canvas" class="wheel-canvas"
width="400" height="400"></canvas>
<div class="wheel-pointer"></div>
</div>
<div class="wheel-controls">
<div class="wheel-stats">
<p>剩余抽奖次数: <span class="spins-left">3</span></p>
<p class="prize-result"></p>
</div>
<button class="spin-button"><?php echo esc_html($atts['button_text']); ?></button>
<button class="reset-spins">重置次数</button>
<div class="wheel-segments">
<h4>奖项设置:</h4>
<ul>
<?php foreach ($segments as $index => $segment): ?>
<li>
<span class="segment-color" style="background-color: <?php echo esc_attr($colors[$index % count($colors)]); ?>"></span>
<?php echo esc_html($segment); ?>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
<div class="wheel-history">
<h4>中奖记录</h4>
<ul class="history-list"></ul>
</div>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
new WheelOfFortune(
'<?php echo esc_js($game_id); ?>',
<?php echo json_encode($segments); ?>,
<?php echo json_encode($colors); ?>,
'<?php echo esc_js($atts['prize_text']); ?>'
);
});
</script>
<?php
return ob_get_clean();
}
创建 /games/js/wheel-game.js 文件:
class WheelOfFortune {
constructor(containerId, segments, colors, prizeText) {
this.container = document.getElementById(containerId);
this.canvas = this.container.querySelector('.wheel-canvas');
this.ctx = this.canvas.getContext('2d');
this.spinButton = this.container.querySelector('.spin-button');
this.resetButton = this.container.querySelector('.reset-spins');
this.prizeResult = this.container.querySelector('.prize-result');
this.spinsLeftElement = this.container.querySelector('.spins-left');
this.historyList = this.container.querySelector('.history-list');
this.segments = segments;
this.colors = colors;
this.prizeText = prizeText;
// 游戏状态
this.spinsLeft = 3;
this.isSpinning = false;
this.currentRotation = 0;
this.segmentAngle = (2 * Math.PI) / this.segments.length;
this.init();
}
init() {
this.drawWheel();
this.setupEventListeners();
this.updateSpinsDisplay();
this.loadHistory();
}
drawWheel() {
const centerX = this.canvas.width / 2;
const centerY = this.canvas.height / 2;
const radius = Math.min(centerX, centerY) - 10;
// 清除画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制每个扇形
for (let i = 0; i < this.segments.length; i++) {
const startAngle = this.currentRotation + (i * this.segmentAngle);
const endAngle = startAngle + this.segmentAngle;
// 绘制扇形
this.ctx.beginPath();
this.ctx.moveTo(centerX, centerY);
this.ctx.arc(centerX, centerY, radius, startAngle, endAngle);
this.ctx.closePath();
// 填充颜色
this.ctx.fillStyle = this.colors[i % this.colors.length];
this.ctx.fill();
// 绘制边框
this.ctx.strokeStyle = '#FFFFFF';
this.ctx.lineWidth = 2;
this.ctx.stroke();
// 绘制文本
this.ctx.save();
this.ctx.translate(centerX, centerY);
this.ctx.rotate(startAngle + this.segmentAngle / 2);
this.ctx.textAlign = 'right';
this.ctx.fillStyle = '#FFFFFF';
this.ctx.font = 'bold 14px Arial';
this.ctx.fillText(this.segments[i], radius - 20, 5);
this.ctx.restore();
}
// 绘制中心圆
this.ctx.beginPath();
this.ctx.arc(centerX, centerY, 20, 0, 2 * Math.PI);
this.ctx.fillStyle = '#333333';
this.ctx.fill();
this.ctx.strokeStyle = '#FFFFFF';
this.ctx.lineWidth = 3;
this.ctx.stroke();
}
setupEventListeners() {
this.spinButton.addEventListener('click', () => this.spinWheel());
this.resetButton.addEventListener('click', () => this.resetSpins());
}
spinWheel() {
if (this.isSpinning || this.spinsLeft <= 0) return;
this.isSpinning = true;
this.spinsLeft--;
this.updateSpinsDisplay();
// 随机决定停止位置
const spinDuration = 3000 + Math.random() * 2000; // 3-5秒
const extraRotation = 5 + Math.random() * 5; // 额外旋转5-10圈
const totalRotation = (extraRotation * 2 * Math.PI) + (Math.random() * this.segmentAngle);
// 动画开始时间
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / spinDuration, 1);
// 缓动函数:先快后慢
const easeOut = 1 - Math.pow(1 - progress, 3);
// 更新旋转角度
this.currentRotation = easeOut * totalRotation;
this.drawWheel();
if (progress < 1) {
requestAnimationFrame(animate);
} else {
// 动画结束
this.isSpinning = false;
this.determinePrize();
}
};
animate();
}
determinePrize() {
// 计算指针指向的扇形
const normalizedRotation = this.currentRotation % (2 * Math.PI);
const segmentIndex = Math.floor(
((2 * Math.PI - normalizedRotation) % (2 * Math.PI)) / this.segmentAngle
);
const prize = this.segments[segmentIndex];
// 显示结果
this.prizeResult.textContent = `${this.prizeText} ${prize}`;
this.prizeResult.style.color = this.colors[segmentIndex % this.colors.length];
// 添加到历史记录
this.addToHistory(prize);
// 保存到本地存储
this.saveHistory(prize);
// 如果是"再来一次",增加一次抽奖机会
if (prize === '再来一次') {
this.spinsLeft++;
this.updateSpinsDisplay();
}
}
addToHistory(prize) {
const now = new Date();
const timeString = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
const historyItem = document.createElement('li');
historyItem.innerHTML = `
<span class="history-time">${timeString}</span>
<span class="history-prize">${prize}</span>
`;
this.historyList.insertBefore(historyItem, this.historyList.firstChild);
// 限制历史记录数量
if (this.historyList.children.length > 10) {
this.historyList.removeChild(this.historyList.lastChild);
}
}
saveHistory(prize) {
const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]');
history.unshift({
prize: prize,
timestamp: new Date().toISOString()
});
// 只保留最近20条记录
const recentHistory = history.slice(0, 20);
localStorage.setItem('wheelGameHistory', JSON.stringify(recentHistory));
}
loadHistory() {
const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]');
history.forEach(item => {
const date = new Date(item.timestamp);
const timeString = date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
const historyItem = document.createElement('li');
historyItem.innerHTML = `
<span class="history-time">${timeString}</span>
<span class="history-prize">${item.prize}</span>
`;
this.historyList.appendChild(historyItem);
});
}
updateSpinsDisplay() {
this.spinsLeftElement.textContent = this.spinsLeft;
if (this.spinsLeft <= 0) {
this.spinButton.disabled = true;
this.spinButton.textContent = '次数已用完';
} else {
this.spinButton.disabled = false;
this.spinButton.textContent = '开始抽奖';
}
}
resetSpins() {
this.spinsLeft = 3;
this.updateSpinsDisplay();
this.prizeResult.textContent = '';
}
}
创建 /games/css/wheel-game.css 文件:
.wheel-game-container {
max-width: 900px;
margin: 30px auto;
padding: 25px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 20px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
color: white;
font-family: 'Arial', sans-serif;
}
.wheel-header {
text-align: center;
margin-bottom: 30px;
}
.wheel-header h3 {
font-size: 32px;
margin-bottom: 10px;
color: #FFD700;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.wheel-header p {
font-size: 18px;
opacity: 0.9;
}
.wheel-content {
display: flex;
flex-wrap: wrap;
gap: 40px;
align-items: center;
justify-content: center;
}
.wheel-wrapper {
position: relative;
flex: 0 0 auto;
}
.wheel-canvas {
background: white;
border-radius: 50%;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
border: 8px solid #FFD700;
}
.wheel-pointer {
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 40px solid #FF0000;
filter: drop-shadow(0 5px 5px rgba(0, 0, 0, 0.3));
z-index: 10;
}
.wheel-controls {
flex: 1;
min-width: 300px;
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 15px;
backdrop-filter: blur(10px);
}
.wheel-stats {
margin-bottom: 25px;
padding: 15px;
background: rgba(0, 0, 0, 0.2);
border-radius: 10px;
}
.wheel-stats p {
font-size: 18px;
margin: 10px 0;
}
.prize-result {
font-size: 22px !important;
font-weight: bold;
color: #FFD700 !important;
min-height: 30px;
margin-top: 15px !important;
}
.wheel-controls button {
display: block;
width: 100%;
padding: 15px;
margin: 10px 0;
border: none;
border-radius: 8px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.spin-button {
background: linear-gradient(45deg, #FF416C, #FF4B2B);
color: white;
}
.spin-button:hover:not(:disabled) {
transform: translateY(-3px);


