文章目录[隐藏]
实战教学:为你的WordPress网站添加在线迷你游戏以提升用户互动与留存
引言:为什么网站需要迷你游戏?
在当今互联网环境中,用户注意力已成为最稀缺的资源之一。网站运营者面临着一个共同的挑战:如何让访客停留更长时间,提高用户参与度,并最终实现转化率的提升?传统的内容展示方式已难以满足现代用户的需求,而互动元素的加入正成为解决这一问题的有效途径。
在线迷你游戏作为一种轻量级互动形式,具有以下优势:
- 提升用户停留时间:有趣的游戏体验能有效延长用户在网站的停留时间
- 增强品牌记忆:通过游戏化体验加深用户对品牌的印象
- 促进社交分享:用户乐于分享游戏成绩和体验,带来自然流量
- 收集用户数据:游戏过程中可以收集有价值的用户行为数据
- 提高转化率:游戏化元素可以作为引导用户完成特定动作的有效手段
本文将详细介绍如何通过WordPress代码二次开发,为你的网站添加实用的在线迷你游戏和小工具功能,从而显著提升用户互动与留存率。
第一部分:准备工作与环境搭建
1.1 选择合适的开发环境
在开始开发之前,确保你拥有以下环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:最新版本的WordPress(建议5.8以上)
- 代码编辑器:VS Code、Sublime Text或PHPStorm
- 浏览器开发者工具:用于调试JavaScript和CSS
1.2 创建子主题保护核心文件
为了避免主题更新导致自定义代码丢失,我们首先创建一个子主题:
/*
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'));
}
1.3 创建必要的目录结构
在你的子主题目录中创建以下文件夹结构:
/my-gamification-theme/
├── games/
│ ├── js/
│ ├── css/
│ └── assets/
├── includes/
├── templates/
└── functions.php
第二部分:实现经典记忆配对游戏
2.1 游戏设计与功能规划
记忆配对游戏是一种简单但有效的互动游戏,适合各种类型的网站。我们将实现以下功能:
- 可配置的卡片数量(4x4、4x5、5x6等)
- 计时器和步数计数器
- 得分系统
- 社交分享功能
- 保存最高分记录
2.2 创建游戏短代码
在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();
}
2.3 实现游戏JavaScript逻辑
创建 /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);
});
});
2.4 添加游戏样式
创建 /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;
}
}
2.5 在WordPress中注册游戏资源
在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
);
}
}
第三部分:创建简易抽奖转盘游戏
3.1 转盘游戏设计与实现
抽奖转盘是另一种受欢迎的互动形式,特别适合电商网站和营销活动。我们将创建一个可配置的转盘游戏:
// 注册转盘游戏短代码
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();
}
3.2 转盘游戏JavaScript实现
创建 /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 = '';
}
}
3.3 转盘游戏样式设计
创建 /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);
