如何使用HTML+JavaScript實現(xiàn)積分抽獎系統(tǒng)
一、積分抽獎系統(tǒng)
在現(xiàn)代 Web 應(yīng)用中,積分抽獎活動已成為提升用戶參與度和留存率的重要手段。本文將詳細介紹一個基于 HTML、CSS 和 JavaScript 實現(xiàn)的九宮格積分抽獎系統(tǒng),該系統(tǒng)具有流暢的動畫效果和良好的用戶體驗。
二、效果演示
該抽獎系統(tǒng)采用經(jīng)典的九宮格布局設(shè)計,中心為抽獎按鈕,周圍八個格子展示不同的獎品選項。用戶點擊"開始抽獎"按鈕后,系統(tǒng)會消耗 100 積分并啟動抽獎動畫,最終高亮顯示中獎結(jié)果并通過彈窗展示獎勵詳情。



三、系統(tǒng)分析
1、頁面結(jié)構(gòu)
頁面采用居中布局,主體容器 container 包含標題、積分信息和抽獎區(qū)域三個主要部分。
1.1 主體容器
<div class="container">
<h1 class="title">積分抽獎</h1>
<div class="points-info">
當前積分:<span class="points" id="currentPoints">1000</span>
</div>
<div class="lottery-grid">
<!-- 九宮格抽獎區(qū)域 -->
</div>
</div>
1.2 九宮格布局
抽獎區(qū)域采用 CSS Grid 布局實現(xiàn) 3×3 的網(wǎng)格結(jié)構(gòu),中心位置放置抽獎按鈕。
<div class="lottery-grid">
<!-- 第一行 -->
<div class="lottery-item" data-index="0">
<div class="item-icon"></div>
<div class="item-name">10積分</div>
<div class="item-points">參與獎</div>
</div>
<div class="lottery-item" data-index="1">
<div class="item-icon"></div>
<div class="item-name">50積分</div>
<div class="item-points">幸運獎</div>
</div>
<div class="lottery-item" data-index="2">
<div class="item-icon"></div>
<div class="item-name">100積分</div>
<div class="item-points">三等獎</div>
</div>
<!-- 第二行 -->
<div class="lottery-item" data-index="7">
<div class="item-icon"></div>
<div class="item-name">500積分</div>
<div class="item-points">特等獎</div>
</div>
<div class="draw-button" id="drawButton" onclick="startDraw()">
<div style="font-size: 24px; margin-bottom: 8px;"></div>
<div>開始抽獎</div>
<div style="font-size: 12px; margin-top: 4px;">消耗: 100積分</div>
</div>
<div class="lottery-item" data-index="3">
<div class="item-icon"></div>
<div class="item-name">20積分</div>
<div class="item-points">鼓勵獎</div>
</div>
<!-- 第三行 -->
<div class="lottery-item" data-index="6">
<div class="item-icon"></div>
<div class="item-name">200積分</div>
<div class="item-points">二等獎</div>
</div>
<div class="lottery-item" data-index="5">
<div class="item-icon"></div>
<div class="item-name">謝謝參與</div>
<div class="item-points">再接再厲</div>
</div>
<div class="lottery-item" data-index="4">
<div class="item-icon"></div>
<div class="item-name">30積分</div>
<div class="item-points">安慰獎</div>
</div>
</div>
1.3結(jié)果彈窗
中獎結(jié)果顯示通過模態(tài)框 result-modal 實現(xiàn)。
<div class="result-modal" id="resultModal" onclick="handleModalClick(event)">
<div class="result-content">
<div class="result-icon" id="resultIcon"></div>
<div class="result-title" id="resultTitle"></div>
<div class="result-desc" id="resultDesc"></div>
<button class="close-btn" onclick="closeResult()">確定</button>
</div>
</div>
2、核心功能實現(xiàn)
2.1 全局變量定義
系統(tǒng)通過下面幾個關(guān)鍵變量管理抽獎狀態(tài):
- currentPoints:用戶當前積分
- drawCost:每次抽獎消耗積分
- isDrawing:抽獎進行狀態(tài)標志
- prizes:獎品配置數(shù)組
let currentPoints = 1000;
let drawCost = 100;
let isDrawing = false;
let prizes = [
{ name: '10積分', points: 10, probability: 25, desc: '恭喜獲得參與獎!' },
// ...其他獎品配置
];
2.2 抽獎流程控制
startDraw 函數(shù)負責控制整個抽獎流程。首先通過 isDrawing 標志位防止重復(fù)觸發(fā),然后檢查用戶積分是否充足,接著扣除抽獎成本、更新界面顯示,清理上一次抽獎的高亮狀態(tài),最后啟動核心的九宮格動畫邏輯 startLotteryAnimation。
function startDraw() {
if (isDrawing) return;
if (currentPoints < drawCost) {
showResult('積分不足', `當前積分:${currentPoints},需要${drawCost}積分才能抽獎!`);
return;
}
isDrawing = true;
currentPoints -= drawCost;
updatePointsDisplay();
updateDrawButtonState(true);
// 清除之前選中狀態(tài)并啟動動畫
document.querySelectorAll('.lottery-item').forEach(item => {
item.classList.remove('active');
});
startLotteryAnimation();
}
2.3 抽獎動畫實現(xiàn)
startLotteryAnimation 函數(shù)實現(xiàn)九宮格循環(huán)高亮的動畫效果。它首先確定總共有8個獎項格子,并設(shè)定基礎(chǔ)轉(zhuǎn)動圈數(shù)為3圈,然后通過 getRandomPrizeIndex 獲取中獎位置,計算出總的動畫步數(shù)。
在動畫過程中,使用遞歸 setTimeout 實現(xiàn)循環(huán)播放,每一步都會移除上一格的高亮狀態(tài)并給當前格添加高亮效果,同時根據(jù)當前步數(shù)動態(tài)調(diào)整動畫速度(前20步加速,最后20步減速),最終在指定步數(shù)停止并調(diào)用 showDrawResult 展示抽獎結(jié)果。
function startLotteryAnimation() {
const totalItems = 8;
const baseRounds = 3;
const finalIndex = getRandomPrizeIndex();
const totalSteps = baseRounds * totalItems + finalIndex;
let currentStep = 0;
let currentIndex = 0;
let previousIndex = -1;
let speed = 50; // 初始速度
const animate = () => {
// 移除前一個元素的 active 類
if (previousIndex !== -1) {
const previousItem = document.querySelector(`[data-index="${previousIndex}"]`);
if (previousItem) {
previousItem.classList.remove('active');
}
}
// 高亮當前格子
const currentItem = document.querySelector(`[data-index="${currentIndex}"]`);
if (currentItem) {
currentItem.classList.add('active');
}
previousIndex = currentIndex;
currentStep++;
// 速度逐漸變慢
if (currentStep > totalSteps - 20) {
speed += 10;
} else if (currentStep < 20) {
speed = Math.max(30, speed - 5);
}
// 更新索引
currentIndex = (currentIndex + 1) % totalItems;
if (currentStep < totalSteps) {
setTimeout(animate, speed);
} else {
// 動畫結(jié)束,顯示結(jié)果
setTimeout(() => {
showDrawResult(finalIndex);
}, 500);
}
};
animate();
}
2.4 概率算法實現(xiàn)
getRandomPrizeIndex 函數(shù)基于概率權(quán)重算法確定中獎結(jié)果。它首先生成一個 0-100 之間的隨機數(shù),然后遍歷 prizes 數(shù)組累加每個獎項的概率值,當隨機數(shù)小于等于累計概率時,就返回當前獎項的索引,從而實現(xiàn)按照預(yù)設(shè)概率分布進行抽獎。如果遍歷完所有獎項都沒有匹配,則默認返回索引0。
function getRandomPrizeIndex() {
const random = Math.random() * 100;
let cumulative = 0;
for (let i = 0; i < prizes.length; i++) {
cumulative += prizes[i].probability;
if (random <= cumulative) {
return i;
}
}
return 0;
}
四、擴展建議
- 增加抽獎次數(shù)限制:可以設(shè)置每日抽獎次數(shù)上限,提高稀缺性
- 豐富獎品種類:添加實物獎品、優(yōu)惠券等非積分獎勵類型
- 歷史記錄功能:記錄用戶抽獎歷史,增強參與感
- 社交分享機制:允許用戶分享中獎結(jié)果,擴大傳播效果
- 主題皮膚切換:提供多種視覺主題隨時選擇切換
- 音效支持:添加背景音樂和音效增強沉浸感
五、完整代碼
<!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;
}
body {
background-color: #f5f5f5;
display: flex;
justify-content: center;
padding: 20px;
}
.container {
background: #FFFFFF;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
text-align: center;
width: 800px;
}
.title {
font-size: 28px;
color: #333;
margin-bottom: 20px;
font-weight: bold;
}
.points-info {
font-size: 18px;
color: #666;
margin-bottom: 30px;
}
.points {
color: #e74c3c;
font-weight: bold;
font-size: 24px;
}
.lottery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 10px;
max-width: 450px;
margin: 0 auto 30px;
aspect-ratio: 1/1;
}
.lottery-item {
border: 3px solid #ddd;
border-radius: 15px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: linear-gradient(145deg, #f8f9fa, #e9ecef);
transition: all 0.3s ease;
cursor: pointer;
position: relative;
overflow: hidden;
font-size: 14px;
}
.lottery-item.active {
border-color: #e74c3c;
background: linear-gradient(145deg, #ff6b6b, #ee5a52);
color: white;
box-shadow: 0 10px 20px rgba(231, 76, 60, 0.3);
z-index: 2;
}
.item-icon {
font-size: 30px;
margin-bottom: 8px;
}
.item-name {
font-size: 14px;
font-weight: bold;
color: #333;
}
.item-points {
font-size: 12px;
color: #666;
margin-top: 4px;
}
.lottery-item.active .item-name,
.lottery-item.active .item-points {
color: white;
}
.draw-button {
grid-column: 2;
grid-row: 2;
border: none;
border-radius: 15px;
background: linear-gradient(145deg, #e74c3c, #c0392b);
color: white;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 8px 16px rgba(231, 76, 60, 0.3);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.draw-button:disabled {
background: linear-gradient(145deg, #95a5a6, #7f8c8d);
cursor: not-allowed;
box-shadow: none;
}
.result-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
.result-content {
background: white;
padding: 40px;
border-radius: 20px;
text-align: center;
max-width: 400px;
width: 90%;
}
.result-icon {
font-size: 60px;
margin-bottom: 20px;
}
.result-title {
font-size: 24px;
color: #333;
margin-bottom: 10px;
font-weight: bold;
}
.result-desc {
font-size: 16px;
color: #666;
margin-bottom: 20px;
}
.close-btn {
background: linear-gradient(145deg, #e74c3c, #c0392b);
color: white;
border: none;
padding: 12px 30px;
border-radius: 25px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
</style>
</head>
<body>
<div class="container">
<h1 class="title">積分抽獎</h1>
<div class="points-info">
當前積分:<span class="points" id="currentPoints">1000</span>
</div>
<div class="lottery-grid">
<!-- 第一行 -->
<div class="lottery-item" data-index="0">
<div class="item-icon"></div>
<div class="item-name">10積分</div>
<div class="item-points">參與獎</div>
</div>
<div class="lottery-item" data-index="1">
<div class="item-icon"></div>
<div class="item-name">50積分</div>
<div class="item-points">幸運獎</div>
</div>
<div class="lottery-item" data-index="2">
<div class="item-icon"></div>
<div class="item-name">100積分</div>
<div class="item-points">三等獎</div>
</div>
<!-- 第二行 -->
<div class="lottery-item" data-index="7">
<div class="item-icon"></div>
<div class="item-name">500積分</div>
<div class="item-points">特等獎</div>
</div>
<div class="draw-button" id="drawButton" onclick="startDraw()">
<div style="font-size: 24px; margin-bottom: 8px;"></div>
<div>開始抽獎</div>
<div style="font-size: 12px; margin-top: 4px;">消耗: 100積分</div>
</div>
<div class="lottery-item" data-index="3">
<div class="item-icon"></div>
<div class="item-name">20積分</div>
<div class="item-points">鼓勵獎</div>
</div>
<!-- 第三行 -->
<div class="lottery-item" data-index="6">
<div class="item-icon"></div>
<div class="item-name">200積分</div>
<div class="item-points">二等獎</div>
</div>
<div class="lottery-item" data-index="5">
<div class="item-icon"></div>
<div class="item-name">謝謝參與</div>
<div class="item-points">再接再厲</div>
</div>
<div class="lottery-item" data-index="4">
<div class="item-icon"></div>
<div class="item-name">30積分</div>
<div class="item-points">安慰獎</div>
</div>
</div>
</div>
<!-- 結(jié)果彈窗 -->
<div class="result-modal" id="resultModal" onclick="handleModalClick(event)">
<div class="result-content">
<div class="result-icon" id="resultIcon"></div>
<div class="result-title" id="resultTitle"></div>
<div class="result-desc" id="resultDesc"></div>
<button class="close-btn" onclick="closeResult()">確定</button>
</div>
</div>
<script>
// 抽獎系統(tǒng)變量
let currentPoints = 1000;
let drawCost = 100;
let isDrawing = false;
let prizes = [
{ name: '10積分', points: 10, probability: 25, desc: '恭喜獲得參與獎!' },
{ name: '50積分', points: 50, probability: 20, desc: '恭喜獲得幸運獎!' },
{ name: '100積分', points: 100, probability: 15, desc: '恭喜獲得三等獎!' },
{ name: '20積分', points: 20, probability: 20, desc: '恭喜獲得鼓勵獎!' },
{ name: '30積分', points: 30, probability: 10, desc: '恭喜獲得安慰獎!' },
{ name: '謝謝參與', points: 0, probability: 5, desc: '很遺憾,再接再厲哦!' },
{ name: '200積分', points: 200, probability: 3, desc: '恭喜獲得二等獎!' },
{ name: '500積分', points: 500, probability: 2, desc: '恭喜獲得特等獎!' }
];
// 更新積分顯示
function updatePointsDisplay() {
document.getElementById('currentPoints').textContent = currentPoints;
}
// 更新抽獎按鈕狀態(tài)
function updateDrawButtonState(isDrawingState) {
const drawButton = document.getElementById('drawButton');
if (isDrawingState) {
drawButton.innerHTML = `
<div style="font-size: 24px; margin-bottom: 8px;"></div>
<div>抽獎中...</div>
`;
} else {
drawButton.innerHTML = `
<div style="font-size: 24px; margin-bottom: 8px;"></div>
<div>開始抽獎</div>
<div style="font-size: 12px; margin-top: 4px;">消耗: 100積分</div>
`;
}
drawButton.disabled = isDrawingState;
}
// 開始抽獎
function startDraw() {
if (isDrawing) return;
if (currentPoints < drawCost) {
showResult('積分不足', `當前積分:${currentPoints},需要${drawCost}積分才能抽獎!`);
return;
}
isDrawing = true;
currentPoints -= drawCost;
updatePointsDisplay();
updateDrawButtonState(true);
// 清除之前的選中狀態(tài)
document.querySelectorAll('.lottery-item').forEach(item => {
item.classList.remove('active');
});
// 開始轉(zhuǎn)盤動畫
startLotteryAnimation();
}
// 開始抽獎動畫
function startLotteryAnimation() {
const totalItems = 8;
const baseRounds = 3; // 基礎(chǔ)轉(zhuǎn)3圈
const finalIndex = getRandomPrizeIndex();
const totalSteps = baseRounds * totalItems + finalIndex;
let currentStep = 0;
let currentIndex = 0;
let previousIndex = -1;
let speed = 50; // 初始速度
const animate = () => {
// 移除前一個元素的 active 類
if (previousIndex !== -1) {
const previousItem = document.querySelector(`[data-index="${previousIndex}"]`);
if (previousItem) {
previousItem.classList.remove('active');
}
}
// 高亮當前格子
const currentItem = document.querySelector(`[data-index="${currentIndex}"]`);
if (currentItem) {
currentItem.classList.add('active');
}
previousIndex = currentIndex;
currentStep++;
// 速度逐漸變慢
if (currentStep > totalSteps - 20) {
speed += 10;
} else if (currentStep < 20) {
speed = Math.max(30, speed - 5);
}
// 更新索引
currentIndex = (currentIndex + 1) % totalItems;
if (currentStep <= totalSteps) {
setTimeout(animate, speed);
} else {
// 動畫結(jié)束,顯示結(jié)果
setTimeout(() => {
showDrawResult(finalIndex);
}, 500);
}
};
animate();
}
// 獲取隨機獎項索引
function getRandomPrizeIndex() {
const random = Math.random() * 100;
let cumulative = 0;
for (let i = 0; i < prizes.length; i++) {
cumulative += prizes[i].probability;
if (random <= cumulative) {
return i;
}
}
return 0;
}
// 顯示抽獎結(jié)果
function showDrawResult(prizeIndex) {
const prize = prizes[prizeIndex];
// 添加中獎積分
if (prize.points > 0) {
currentPoints += prize.points;
updatePointsDisplay();
}
// 恢復(fù)按鈕狀態(tài)
updateDrawButtonState(false);
isDrawing = false;
// 顯示結(jié)果彈窗
showResult(
prize.name,
prize.desc + (prize.points > 0 ? `
獲得${prize.points}積分!` : '')
);
}
// 顯示結(jié)果彈窗
function showResult(title, desc) {
document.getElementById('resultTitle').textContent = title;
document.getElementById('resultDesc').innerHTML = desc;
document.getElementById('resultModal').style.display = 'flex';
}
// 關(guān)閉結(jié)果彈窗
function closeResult() {
document.getElementById('resultModal').style.display = 'none';
}
// 處理模態(tài)框點擊事件
function handleModalClick(event) {
if (event.target === document.getElementById('resultModal')) {
closeResult();
}
}
</script>
</body>
</html>
總結(jié)
到此這篇關(guān)于如何使用HTML+JavaScript實現(xiàn)積分抽獎系統(tǒng)的文章就介紹到這了,更多相關(guān)HTML+JS積分抽獎系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript基于數(shù)組實現(xiàn)的棧與隊列操作示例
這篇文章主要介紹了JavaScript基于數(shù)組實現(xiàn)的棧與隊列操作,結(jié)合實例形式分析了棧與隊列的操作原理及javascript使用數(shù)組實現(xiàn)棧與隊列的相關(guān)技巧,需要的朋友可以參考下2018-12-12
刷新頁面實現(xiàn)方式總結(jié)(HTML,ASP,JS)
多種方法實現(xiàn)頁面的刷新代碼2008-11-11
基于JavaScript+IntersectionObserver實現(xiàn)高性能圖片懶加載
在 Web 開發(fā)中,圖片懶加載是一種常見的優(yōu)化手段,尤其在長列表頁面中,按需加載圖片可以顯著提升頁面性能,本篇文章將通過 JavaScript 和 Intersection Observer,實現(xiàn)一個帶有卡片樣式的高性能圖片懶加載示例,需要的朋友可以參考下2025-01-01
jquery及js實現(xiàn)動態(tài)加載js文件的方法
這篇文章主要介紹了jquery及js實現(xiàn)動態(tài)加載js文件的方法,結(jié)合實例形式分別講述了基于jQuery以及基于JavaScript的文件動態(tài)加載方法,需要的朋友可以參考下2016-01-01
javascript實現(xiàn)獲取圖片大小及圖片等比縮放的方法
這篇文章主要介紹了javascript實現(xiàn)獲取圖片大小及圖片等比縮放的方法,涉及javascript針對圖形圖像相關(guān)屬性獲取與修改相關(guān)操作技巧,需要的朋友可以參考下2016-11-11

