- 高亮当前奖项,清除其他奖项高亮样式,function highlightNext()
- 转圈先快后慢,通过settimeout(highlightNext(),延时时间) 的 延时时间控制,这里递归调用 function highlightNext(),出口是指定的步数
- 作弊指定目标奖项,最终停到某个奖项
效果图:
详细代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>移动云盘 - 幸运抽奖</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}
body {
background: linear-gradient(135deg, #1a5f23, #0d8b58);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.container {
width: 100%;
max-width: 500px;
text-align: center;
}
.header {
margin-bottom: 30px;
padding: 15px;
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
backdrop-filter: blur(5px);
}
.header h1 {
color: #fff;
font-size: 28px;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.header p {
color: #e0f7e0;
font-size: 16px;
}
.lottery-box {
background: rgba(255, 255, 255, 0.15);
border-radius: 20px;
padding: 30px 20px 20px;
position: relative;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
}
.lottery-box::before {
content: "";
position: absolute;
top: -8px;
left: -8px;
right: -8px;
bottom: -8px;
border: 2px dashed rgba(60, 179, 113, 0.5);
border-radius: 25px;
pointer-events: none;
z-index: -1;
}
.prize-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 15px;
margin-bottom: 25px;
}
.prize-item {
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
padding: 15px 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 120px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
border: 1px solid rgba(46, 139, 87, 0.3);
}
.prize-item.active {
background: linear-gradient(145deg, #fff9c4, #ffeb3b);
box-shadow: 0 0 20px #ffeb3b, 0 0 30px rgba(255, 235, 59, 0.5);
transform: scale(1.08);
z-index: 2;
animation: pulse 1s infinite alternate;
}
@keyframes pulse {
from { box-shadow: 0 0 15px #ffeb3b; }
to { box-shadow: 0 0 30px #ffeb3b; }
}
.prize-item .prize-name {
font-size: 15px;
font-weight: bold;
color: #2e8b57;
margin-bottom: 6px;
}
.prize-item .prize-desc {
font-size: 12px;
color: #666;
}
.draw-btn {
/* grid-column: 2;
grid-row: 2;
background: linear-gradient(145deg, #ff5252, #ff0000);
color: white;
border: none;
border-radius: 50%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 6px 12px rgba(0,0,0,0.25);
transition: all 0.3s ease; */
}
.draw-btn:hover {
transform: scale(1.08);
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
}
.draw-btn:disabled {
background: linear-gradient(145deg, #cccccc, #999999);
cursor: not-allowed;
transform: scale(1);
}
.chances-left {
margin-top: 15px;
font-size: 16px;
color: #ffeb3b;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.result-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
justify-content: center;
align-items: center;
z-index: 100;
}
.result-content {
background: linear-gradient(145deg, #ffffff, #f0f8f0);
padding: 35px;
border-radius: 20px;
text-align: center;
max-width: 85%;
width: 400px;
animation: popIn 0.6s ease;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
position: relative;
overflow: hidden;
border: 2px solid #ffeb3b;
}
.result-content::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8px;
background: linear-gradient(90deg, #ff5252, #ffeb3b, #2e8b57);
}
@keyframes popIn {
0% { transform: scale(0.5); opacity: 0; }
70% { transform: scale(1.1); }
100% { transform: scale(1); opacity: 1; }
}
.result-content h2 {
color: #2e8b57;
margin-bottom: 20px;
font-size: 28px;
}
.result-content p {
margin: 15px 0;
font-size: 18px;
color: #333;
}
.result-content .prize-won {
font-size: 24px;
font-weight: bold;
color: #ff5252;
margin: 20px 0;
padding: 15px;
background: rgba(255, 235, 59, 0.2);
border-radius: 10px;
border: 2px dashed #ff5252;
}
.close-btn {
background: linear-gradient(145deg, #2e8b57, #1a5f23);
color: white;
border: none;
padding: 12px 30px;
border-radius: 50px;
cursor: pointer;
margin-top: 20px;
font-size: 18px;
font-weight: bold;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transition: all 0.3s ease;
}
.close-btn:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
.music-icon {
position: absolute;
top: 8px;
right: 8px;
font-size: 14px;
color: #ff6b6b;
font-weight: bold;
background: rgba(255, 107, 107, 0.1);
padding: 2px 6px;
border-radius: 10px;
}
.cloud-icon {
position: absolute;
top: 8px;
left: 8px;
font-size: 14px;
color: #42a5f5;
font-weight: bold;
background: rgba(66, 165, 245, 0.1);
padding: 2px 6px;
border-radius: 10px;
}
.pointer {
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-top: 25px solid #ff5252;
z-index: 5;
filter: drop-shadow(0 3px 5px rgba(0,0,0,0.3));
}
.instructions {
margin-top: 25px;
color: #e0f7e0;
font-size: 14px;
background: rgba(0,0,0,0.15);
padding: 10px;
border-radius: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>移动云盘幸运抽奖</h1>
<p>点击抽奖按钮,赢取丰厚奖品!</p>
</div>
<div class="lottery-box">
<div class="pointer"></div>
<div class="prize-grid">
<!-- 0 -->
<div class="prize-item">
<div class="cloud-icon">云</div>
<div class="prize-name">移动云盘</div>
<div class="prize-desc">白银会员季卡</div>
</div>
<!-- 1 -->
<div class="prize-item">
<div class="prize-name">100M流量日包</div>
</div>
<!-- 2 -->
<div class="prize-item">
<div class="music-icon">Music</div>
<div class="prize-name">咪咕音乐</div>
<div class="prize-desc">30GB定向流量</div>
</div>
<!-- 3 -->
<div class="prize-item">
<div class="prize-name">2GB流量日包</div>
</div>
<!-- 4 -->
<div class="prize-item draw-btn" id="drawBtn">
<!-- <button class="draw-btn" id="drawBtn">抽</button> -->
<p class="draw-btn-title">抽</p>
<p class="remain-text" id="chancesLeft">剩余2次机会</p>
</div>
<!-- 5 -->
<div class="prize-item">
<div class="prize-name">4GB流量日包</div>
</div>
<!-- 6 -->
<div class="prize-item">
<div class="prize-name">1GB流量日包</div>
</div>
<!-- 7 -->
<div class="prize-item">
<div class="prize-name">500M流量日包</div>
</div>
<!-- 8 -->
<div class="prize-item">
<div class="prize-name">谢谢参与</div>
</div>
</div>
</div>
<div class="chances-left" id="chancesLeft">剩余3次机会</div>
</div>
<!-- <div class="instructions">
提示:抽奖结果由指针停止位置决定,停止在哪个奖品上就获得哪个奖品
</div> -->
</div>
<div class="result-modal" id="resultModal">
<div class="result-content">
<h2>抽奖结果</h2>
<p id="resultText">恭喜您获得:</p>
<div class="prize-won" id="prizeWon"></div>
<p id="chancesAfter">剩余2次机会</p>
<button class="close-btn" id="closeBtn">确定</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const drawBtn = document.getElementById('drawBtn');
const chancesLeft = document.getElementById('chancesLeft');
const resultModal = document.getElementById('resultModal');
const resultText = document.getElementById('resultText');
const prizeWon = document.getElementById('prizeWon');
const chancesAfter = document.getElementById('chancesAfter');
const closeBtn = document.getElementById('closeBtn');
const prizeItems = document.querySelectorAll('.prize-item');
let chances = 3;
let isDrawing = false;
let currentPosition = 0; // 当前高亮位置
// 奖品列表(与DOM中的奖品顺序一致)
const prizes = [
"移动云盘白银会员季卡",
"100M流量日包",
"咪咕音乐30GB定向流量",
"2GB流量日包",
"哈哈",
"4GB流量日包",
"1GB流量日包",
"500M流量日包",
"谢谢参与"
];
// 修复:正确的顺时针顺序索引(基于DOM中的实际位置)
// 左上(0) -> 中上(1) -> 右上(2)
// -> 右中(5) -> 右下(8)
// -> 中下(7) -> 左下(6)
// -> 左中(3)
/***
0 1 2
3 4 5
6 7 8
*/
// 对应prizeItems索引: [0, 1, 2, 4, 7, 6, 5, 3]
const clockwiseOrder = [0, 1, 2, 5, 8, 7, 6, 3];
// 更新剩余次数显示
function updateChances() {
chancesLeft.textContent = `剩余${chances}次机会`;
if (chances === 0) {
drawBtn.disabled = true;
drawBtn.textContent = "结束";
}
}
// 抽奖函数 (最终停止的位置 跟 rounds有关 所以我让 rounds等于40+ 0-8的随机数。)
function drawPrize() {
if (isDrawing || chances <= 0) return;
isDrawing = true;
chances--;
updateChances();
drawBtn.disabled = true;
// let rounds = 40 //步数 40步,8个奖项,算转5圈
// let rounds = 40 + Math.floor(Math.random() * 8); // 旋转圈数
let rounds = 40 + 8 // + 多少就能得到对应的奖品(可作弊获得指定奖品)clockwiseOrder[8] 是节点为3的奖品,顺时针推
let speed = 50; // 初始速度
// 高亮动画函数
function highlightNext() {
// 移除所有高亮
prizeItems.forEach(item => item.classList.remove('active'));
// 获取当前步骤对应的DOM索引
const currentIndex = clockwiseOrder[currentPosition];
// 高亮当前项(确保索引在有效范围内)
if (currentIndex >= 0 && currentIndex < prizeItems.length) {
prizeItems[currentIndex].classList.add('active');
}
rounds--;
// 优化减速逻辑
if (rounds > 30) {
// 前10步快速旋转
speed = 50;
} else if (rounds > 20) {
// 开始减速
speed = 100;
} else if (rounds > 10) {
// 进一步减速
speed = 200;
} else if (rounds > 5) {
// 明显减速
speed = 300;
} else {
// 最后几步非常慢
speed = 400;
}
// 继续动画或停止
if (rounds > 0) {
// 移动到下一个位置
currentPosition = (currentPosition + 1) % clockwiseOrder.length;
setTimeout(highlightNext, speed);
console.log(currentPosition);
} else {
console.log(currentPosition);
// 确保最终停在当前位置
prizeItems.forEach(item => item.classList.remove('active'));
// 找到获奖项对应的DOM索引
let winningDomIndex = clockwiseOrder[currentPosition];
if (winningDomIndex >= 0 && winningDomIndex < prizeItems.length) {
prizeItems[winningDomIndex].classList.add('active');
}
// 显示结果
setTimeout(showResult, 800, winningDomIndex);
currentPosition = 0
}
}
// 开始动画
highlightNext();
}
// 显示抽奖结果
function showResult(prizeIndex) {
// 确保索引在有效范围内
if (prizeIndex < 0 || prizeIndex >= prizes.length) {
prizeIndex = 0; // 默认第一个奖品
}
const prize = prizes[prizeIndex];
prizeWon.textContent = prize;
if (prize === "谢谢参与") {
resultText.textContent = "很遗憾,您未中奖";
prizeWon.textContent = "";
} else {
resultText.textContent = "恭喜您获得:";
}
chancesAfter.textContent = `剩余${chances}次机会`;
resultModal.style.display = "flex";
isDrawing = false;
if (chances > 0) {
drawBtn.disabled = false;
}
}
// 关闭结果弹窗
function closeModal() {
resultModal.style.display = "none";
prizeItems.forEach(item => item.classList.remove('active'));
}
// 事件监听
drawBtn.addEventListener('click', drawPrize);
closeBtn.addEventListener('click', closeModal);
// 初始化
updateChances();
});
</script>
</body>
</html>