概述
隨機數生成器是一個功能豐富的線上工具,專為遊戲、決策、抽籤等場景設計,能夠提供多種隨機模式的專業生成功能。 本工具採用純前端架構,完全在瀏覽器端運行,零網路傳輸,確保數據的絕對隱私和安全性。 提供擲硬幣、擲骰子、自訂範圍生成、音效回饋、歷史記錄管理、雙語系統等專業功能。
🔒 隱私保護承諾
🔒 Privacy Protection Promise
所有隨機數生成處理都在您的瀏覽器本地進行,數據不會上傳到任何伺服器,確保您的使用記錄完全安全。
技術架構與核心設計
整體架構設計
Overall Architecture Design
技術項目 | 實作方式 | 設計考量 |
---|---|---|
隨機數生成 | Math.random() + 安全性增強 | 跨平台兼容性,真隨機性 |
音效系統 | Web Audio API + 振盪器 | 即時音效回饋,使用者體驗 |
視覺動畫 | CSS3 動畫 + JavaScript | 流暢動畫效果,視覺回饋 |
歷史管理 | LocalStorage + JSON | 持久化存儲,快速存取 |
雙語系統 | 全域事件 + 本地翻譯 | 實時切換,完整國際化 |
核心算法特色
Core Algorithm Features
- 多模式生成:擲硬幣、擲骰子、自訂範圍三種主要模式
- 音效整合:Web Audio API 實現的動態音效系統
- 視覺回饋:硬幣翻轉和骰子滾動的真實動畫效果
- 歷史追蹤:完整的操作記錄和時間戳記系統
- 參數驗證:輸入範圍檢查和錯誤處理機制
- 響應式設計:支援桌面、平板、手機多種設備
關鍵功能與特色
🪙 擲硬幣模式
🪙 Coin Flip Mode
經典的正反面選擇,配有硬幣翻轉動畫效果和音效回饋
🎲 擲骰子模式
🎲 Dice Roll Mode
支援 D4-D100 多種骰子類型,可同時擲多顆骰子
🔢 自訂範圍模式
🔢 Custom Range Mode
靈活設定最小值、最大值、數量,支援重複/不重複選項
🎵 音效系統
🎵 Audio System
Web Audio API 實現的即時音效,為不同操作提供聽覺回饋
📜 歷史記錄
📜 History Records
自動記錄所有操作結果,支援查看、複製、清除功能
🌐 雙語系統
🌐 Bilingual System
完整的中英文支援,實時語言切換不影響操作流程
實作細節
以下是完整程式碼實作,按功能模組分類展示。點擊卡片標題可展開查看詳細程式碼:
📦 核心隨機數生成器類別
說明:RandomNumberGenerator 類別是整個工具的核心,負責管理所有隨機生成功能、狀態管理、翻譯系統和使用者互動。
🎯 主要功能:
- 狀態管理:維護當前語言、歷史記錄、最後結果等狀態
- 翻譯系統:完整的中英文翻譯字典和動態切換
- 音效控制:Web Audio API 的初始化和管理
- 事件處理:全域語言事件監聽和響應
class RandomNumberGenerator {
constructor() {
// 🎯 核心狀態管理
this.currentLanguage = 'zh'; // 當前語言設定
this.history = JSON.parse(localStorage.getItem('rng-history') || '[]'); // 歷史記錄
this.lastResult = ''; // 最後一次結果
this.audioContext = null; // 音效上下文
this.sounds = {}; // 音效快取
// 🌐 完整的雙語翻譯字典
this.translations = {
zh: {
// 主要介面文字
mainTitle: '🎲 隨機數生成器',
mainDescription: '專業隨機數生成工具,支援多種隨機模式,適合遊戲、決策、抽籤等場景',
// 標籤文字
tabCoin: '🪙 擲硬幣',
tabDice: '🎲 擲骰子',
tabCustom: '🔢 自訂範圍',
// 按鈕文字
flipBtn: '擲硬幣',
rollBtn: '擲骰子',
generateBtn: '產生隨機數',
// 預設結果文字
coinResultDefault: '點擊擲硬幣開始',
diceResultDefault: '選擇骰子類型後開始擲骰',
customResultDefault: '設定參數後開始產生',
// 表單標籤
diceTypeLabel: '骰子類型:',
diceCountLabel: '擲骰次數:',
customSidesLabel: '自訂面數:',
minValueLabel: '最小值:',
maxValueLabel: '最大值:',
numberCountLabel: '產生數量:',
allowDuplicatesLabel: '允許重複',
// 功能按鈕
copyBtn: '📋 複製結果',
shareBtn: '📤 分享結果',
historyBtn: '📜 顯示歷史',
clearBtn: '🗑️ 清除歷史',
historyTitle: '操作歷史',
// 結果相關
heads: '正面',
tails: '反面',
result: '結果',
coinFlip: '擲硬幣',
diceRoll: '擲骰子',
numberGen: '隨機數生成',
// 用戶回饋訊息
copied: '結果已複製到剪貼簿',
shared: '結果已準備分享',
historyCleared: '歷史記錄已清除',
invalidRange: '無效範圍:最大值必須大於最小值',
tooManyNumbers: '產生數量不能超過範圍大小(當不允許重複時)',
// 驗證訊息
diceCountRange: '擲骰次數必須在 1-20 之間',
customSidesRange: '自訂面數必須在 2-1000 之間',
numberCountRange: '產生數量必須在 1-100 之間',
noResultToCopy: '沒有結果可複製',
noResultToShare: '沒有結果可分享',
confirmClearHistory: '確定要清除所有歷史記錄嗎?',
shareTitle: '隨機數生成器結果',
hideHistory: '📜 隱藏歷史',
showHistory: '📜 顯示歷史'
},
en: {
// 主要介面文字
mainTitle: '🎲 Random Number Generator',
mainDescription: 'Professional random number generation tool supporting multiple modes for games, decisions, and draws',
// 標籤文字
tabCoin: '🪙 Coin Flip',
tabDice: '🎲 Dice Roll',
tabCustom: '🔢 Custom Range',
// 按鈕文字
flipBtn: 'Flip Coin',
rollBtn: 'Roll Dice',
generateBtn: 'Generate Numbers',
// 預設結果文字
coinResultDefault: 'Click to flip coin',
diceResultDefault: 'Select dice type to start rolling',
customResultDefault: 'Set parameters to generate',
// 表單標籤
diceTypeLabel: 'Dice Type:',
diceCountLabel: 'Roll Count:',
customSidesLabel: 'Custom Sides:',
minValueLabel: 'Min Value:',
maxValueLabel: 'Max Value:',
numberCountLabel: 'Count:',
allowDuplicatesLabel: 'Allow Duplicates',
// 功能按鈕
copyBtn: '📋 Copy Result',
shareBtn: '📤 Share Result',
historyBtn: '📜 Show History',
clearBtn: '🗑️ Clear History',
historyTitle: 'Operation History',
// 結果相關
heads: 'Heads',
tails: 'Tails',
result: 'Result',
coinFlip: 'Coin Flip',
diceRoll: 'Dice Roll',
numberGen: 'Number Generation',
// 用戶回饋訊息
copied: 'Result copied to clipboard',
shared: 'Result ready to share',
historyCleared: 'History cleared',
invalidRange: 'Invalid range: max value must be greater than min value',
tooManyNumbers: 'Count cannot exceed range size (when duplicates not allowed)',
// 驗證訊息
diceCountRange: 'Dice count must be between 1-20',
customSidesRange: 'Custom sides must be between 2-1000',
numberCountRange: 'Number count must be between 1-100',
noResultToCopy: 'No result to copy',
noResultToShare: 'No result to share',
confirmClearHistory: 'Are you sure you want to clear all history?',
shareTitle: 'Random Number Generator Result',
hideHistory: '📜 Hide History',
showHistory: '📜 Show History'
}
};
// 🚀 初始化應用
this.init();
}
// 🎯 主要初始化方法
init() {
this.setupEventListeners(); // 設定事件監聽器
this.initAudio(); // 初始化音效系統
this.updateLanguage(); // 設定初始語言
}
}
🌐 全域語言系統整合
說明:實現與全站語言系統的無縫整合,確保語言切換的即時性和一致性。處理初始化時序問題,確保工具在各種載入情況下都能正確響應語言變更。
🎯 關鍵實作:
- 全域事件監聽:監聽 languageChanged 事件實現即時切換
- 時序處理:解決全域語言系統載入時序問題
- 狀態同步:確保工具語言狀態與全站同步
- 動態更新:實時更新所有介面文字元素
// 🌐 全域語言系統整合方法
setupGlobalLanguageListener() {
// 🎯 監聽全域語言切換事件
window.addEventListener('languageChanged', (event) => {
this.currentLanguage = event.detail.language;
this.updateLanguage();
console.log(`🌐 語言已切換為: ${this.currentLanguage}`);
});
// 🔄 處理初始化時序問題
// 由於全域語言系統可能在工具初始化後才載入
// 需要智能檢測和重試機制
const checkGlobalLanguage = () => {
if (window.globalI18n) {
// ✅ 全域語言系統已載入
this.currentLanguage = window.globalI18n.currentLanguage;
this.updateLanguage();
console.log(`🔗 已同步全域語言: ${this.currentLanguage}`);
return true;
}
return false;
};
// 🚀 立即檢查,如果沒有就延遲重試
if (!checkGlobalLanguage()) {
setTimeout(() => {
checkGlobalLanguage();
}, 100);
}
}
// 🎨 語言更新核心方法
updateLanguage() {
const t = this.translations[this.currentLanguage];
// 🎯 手動更新所有文字元素
// 主標題和描述
const mainTitle = document.getElementById('main-title');
const mainDescription = document.getElementById('main-description');
if (mainTitle) mainTitle.textContent = t.mainTitle;
if (mainDescription) mainDescription.textContent = t.mainDescription;
// 🏷️ 標籤按鈕
const updateElement = (id, text) => {
const element = document.getElementById(id);
if (element) element.textContent = text;
};
updateElement('tab-coin', t.tabCoin);
updateElement('tab-dice', t.tabDice);
updateElement('tab-custom', t.tabCustom);
// 🔘 主要按鈕
updateElement('flip-btn', t.flipBtn);
updateElement('roll-btn', t.rollBtn);
updateElement('generate-btn', t.generateBtn);
// 🏷️ 表單標籤
updateElement('dice-type-label', t.diceTypeLabel);
updateElement('dice-count-label', t.diceCountLabel);
updateElement('custom-sides-label', t.customSidesLabel);
updateElement('min-value-label', t.minValueLabel);
updateElement('max-value-label', t.maxValueLabel);
updateElement('number-count-label', t.numberCountLabel);
updateElement('allow-duplicates-label', t.allowDuplicatesLabel);
// 🛠️ 功能按鈕
updateElement('copy-btn', t.copyBtn);
updateElement('share-btn', t.shareBtn);
updateElement('history-btn', t.historyBtn);
updateElement('clear-btn', t.clearBtn);
updateElement('history-title', t.historyTitle);
// 📄 預設結果文字
updateElement('coin-result-text', t.coinResultDefault);
updateElement('dice-result-text', t.diceResultDefault);
updateElement('custom-result-text', t.customResultDefault);
// 🔄 移除結果的 has-result 類別以重置樣式
const resultElements = document.querySelectorAll('.result-display');
resultElements.forEach(el => el.classList.remove('has-result'));
console.log(`✅ 語言更新完成: ${this.currentLanguage}`);
}
🎯 DOM 初始化與事件綁定
說明:setupEventListeners 方法負責建立所有使用者互動的事件處理機制,包含標籤切換、骰子設定變更、鍵盤快捷鍵等核心功能。
🎯 主要功能:
- 標籤切換:擲硬幣、擲骰子、自訂範圍三種模式切換
- 動態控制:骰子類型變更時顯示/隱藏自訂面數
- 鍵盤支援:Enter 鍵快捷執行當前模式
- 語言整合:與全域語言系統的事件連結
// 🎯 完整的事件監聽器設置
setupEventListeners() {
// 🏷️ 標籤切換事件處理
document.querySelectorAll('.rng-tab').forEach(tab => {
tab.addEventListener('click', (e) => {
const targetTab = e.target.dataset.tab;
this.switchTab(targetTab);
console.log(`🔄 切換到標籤: ${targetTab}`);
});
});
// 🌐 設置全域語言監聽器(必須最先執行)
this.setupGlobalLanguageListener();
// 🎲 骰子類型變更事件
const diceTypeSelect = document.getElementById('dice-type');
if (diceTypeSelect) {
diceTypeSelect.addEventListener('change', (e) => {
const customGroup = document.getElementById('custom-sides-group');
if (e.target.value === 'custom') {
// 🔧 顯示自訂面數輸入框
customGroup.style.display = 'block';
console.log('🎲 啟用自訂骰子面數');
} else {
// 🔒 隱藏自訂面數輸入框
customGroup.style.display = 'none';
console.log(`🎲 選擇標準骰子: D${e.target.value}`);
}
});
}
// ⌨️ 鍵盤快捷鍵支援
document.addEventListener('keydown', (e) => {
// 🎯 Enter 鍵觸發當前活動標籤的功能
if (e.key === 'Enter') {
const activeTab = document.querySelector('.rng-tab.active');
if (activeTab) {
const tabType = activeTab.dataset.tab;
switch (tabType) {
case 'coin':
this.flipCoin();
console.log('⌨️ 鍵盤觸發擲硬幣');
break;
case 'dice':
this.rollDice();
console.log('⌨️ 鍵盤觸發擲骰子');
break;
case 'custom':
this.generateNumbers();
console.log('⌨️ 鍵盤觸發自訂生成');
break;
}
}
}
// 🔢 數字鍵 1-3 快速切換標籤
if (e.key >= '1' && e.key <= '3' && !e.ctrlKey && !e.altKey) {
const tabMapping = {
'1': 'coin',
'2': 'dice',
'3': 'custom'
};
const targetTab = tabMapping[e.key];
if (targetTab) {
this.switchTab(targetTab);
console.log(`⌨️ 數字鍵切換到: ${targetTab}`);
}
}
});
console.log('✅ 所有事件監聽器已設置完成');
}
// 🔄 標籤切換核心方法
switchTab(tabName) {
// 🎯 更新標籤按鈕狀態
document.querySelectorAll('.rng-tab').forEach(tab => {
tab.classList.remove('active');
});
const targetTab = document.querySelector(`[data-tab="${tabName}"]`);
if (targetTab) {
targetTab.classList.add('active');
}
// 🎯 更新內容顯示狀態
document.querySelectorAll('.rng-content').forEach(content => {
content.classList.remove('active');
});
const targetContent = document.getElementById(`${tabName}-content`);
if (targetContent) {
targetContent.classList.add('active');
}
console.log(`✅ 標籤切換完成: ${tabName}`);
}
⚙️ 隨機數生成處理引擎
說明:三個核心生成方法實現不同類型的隨機數生成,每個方法都包含完整的參數驗證、動畫效果、音效回饋和結果處理機制。
🎯 主要功能:
- 擲硬幣:50/50 機率生成,配合硬幣翻轉動畫
- 擲骰子:支援多種骰子類型,可同時擲多顆
- 自訂範圍:靈活的數值範圍和數量設定
- 參數驗證:完整的輸入檢查和錯誤處理
// 🪙 擲硬幣核心方法
flipCoin() {
const coin = document.getElementById('coin');
const coinFace = document.getElementById('coin-face');
const result = document.getElementById('coin-result');
const resultText = document.getElementById('coin-result-text');
const flipBtn = document.getElementById('flip-btn');
// 🎵 播放音效
this.playSound('coin');
// 🔒 禁用按鈕防止重複點擊
flipBtn.disabled = true;
// 🌀 開始翻轉動畫
coin.classList.add('flipping');
coinFace.textContent = '🌀'; // 旋轉圖示
resultText.textContent = this.translations[this.currentLanguage].result + '...';
// 🎯 生成隨機結果(50/50機率)
const isHeads = Math.random() < 0.5;
// ⏰ 延遲顯示結果營造懸念
setTimeout(() => {
// 🎭 停止動畫並顯示結果
coin.classList.remove('flipping');
coinFace.textContent = isHeads ? '👑' : '⭐'; // 正面/反面圖示
// 🏷️ 根據當前語言顯示結果
const resultStr = isHeads ?
this.translations[this.currentLanguage].heads :
this.translations[this.currentLanguage].tails;
resultText.textContent = `${this.translations[this.currentLanguage].result}:${resultStr}`;
result.classList.add('has-result'); // 套用結果樣式
// 📝 儲存結果並加入歷史
this.lastResult = `${this.translations[this.currentLanguage].coinFlip}: ${resultStr}`;
this.addToHistory(this.lastResult);
// 🔓 重新啟用按鈕
flipBtn.disabled = false;
console.log(`🪙 擲硬幣結果: ${resultStr}`);
}, 2000); // 2秒動畫時間
}
// 🎲 擲骰子核心方法
rollDice() {
const diceType = document.getElementById('dice-type').value;
const diceCount = parseInt(document.getElementById('dice-count').value);
const customSides = parseInt(document.getElementById('custom-sides').value);
const display = document.getElementById('dice-display');
const result = document.getElementById('dice-result');
const resultText = document.getElementById('dice-result-text');
const rollBtn = document.getElementById('roll-btn');
// ✅ 驗證擲骰次數
if (diceCount < 1 || diceCount > 20) {
alert(this.translations[this.currentLanguage].diceCountRange);
return;
}
// 🎯 決定骰子面數
let sides;
if (diceType === 'custom') {
// ✅ 驗證自訂面數
if (customSides < 2 || customSides > 1000) {
alert(this.translations[this.currentLanguage].customSidesRange);
return;
}
sides = customSides;
} else {
sides = parseInt(diceType);
}
// 🎵 播放音效
this.playSound('dice');
// 🔒 禁用按鈕
rollBtn.disabled = true;
// 🧹 清空顯示區域
display.innerHTML = '';
resultText.textContent = this.translations[this.currentLanguage].result + '...';
// 🎲 創建骰子視覺元素
const diceElements = [];
for (let i = 0; i < diceCount; i++) {
const dice = document.createElement('div');
dice.className = 'dice rolling'; // 滾動動畫樣式
dice.textContent = '?'; // 初始顯示問號
display.appendChild(dice);
diceElements.push(dice);
}
// 🎯 生成所有骰子的隨機結果
const results = [];
for (let i = 0; i < diceCount; i++) {
results.push(Math.floor(Math.random() * sides) + 1);
}
// ⏰ 延遲顯示結果
setTimeout(() => {
// 🎭 更新每個骰子的顯示
diceElements.forEach((dice, index) => {
dice.classList.remove('rolling');
dice.textContent = results[index];
});
// 📊 計算並顯示結果
const sum = results.reduce((a, b) => a + b, 0);
const resultStr = diceCount === 1 ?
`${results[0]}` :
`${results.join(', ')} (總和: ${sum})`;
resultText.textContent = `${this.translations[this.currentLanguage].result}:${resultStr}`;
result.classList.add('has-result');
// 📝 儲存結果
this.lastResult = `${this.translations[this.currentLanguage].diceRoll} D${sides}: ${resultStr}`;
this.addToHistory(this.lastResult);
// 🔓 重新啟用按鈕
rollBtn.disabled = false;
console.log(`🎲 擲骰結果: ${resultStr}`);
}, 1500); // 1.5秒動畫時間
}
// 🔢 自訂範圍隨機數生成方法
generateNumbers() {
const minValue = parseInt(document.getElementById('min-value').value);
const maxValue = parseInt(document.getElementById('max-value').value);
const numberCount = parseInt(document.getElementById('number-count').value);
const allowDuplicates = document.getElementById('allow-duplicates').checked;
const result = document.getElementById('custom-result');
const resultText = document.getElementById('custom-result-text');
const generateBtn = document.getElementById('generate-btn');
// ✅ 驗證數值範圍
if (minValue >= maxValue) {
alert(this.translations[this.currentLanguage].invalidRange);
return;
}
// ✅ 驗證生成數量
if (numberCount < 1 || numberCount > 100) {
alert(this.translations[this.currentLanguage].numberCountRange);
return;
}
// ✅ 驗證不重複模式下的數量限制
const range = maxValue - minValue + 1;
if (!allowDuplicates && numberCount > range) {
alert(this.translations[this.currentLanguage].tooManyNumbers);
return;
}
// 🔒 禁用按鈕
generateBtn.disabled = true;
resultText.textContent = this.translations[this.currentLanguage].result + '...';
// 🎯 生成隨機數陣列
const numbers = [];
if (allowDuplicates) {
// 🔄 允許重複:簡單隨機生成
for (let i = 0; i < numberCount; i++) {
numbers.push(Math.floor(Math.random() * range) + minValue);
}
} else {
// 🚫 不允許重複:洗牌演算法
const available = [];
for (let i = minValue; i <= maxValue; i++) {
available.push(i);
}
// Fisher-Yates 洗牌演算法
for (let i = 0; i < numberCount; i++) {
const randomIndex = Math.floor(Math.random() * available.length);
numbers.push(available.splice(randomIndex, 1)[0]);
}
}
// ⏰ 短暫延遲增加期待感
setTimeout(() => {
// 🎨 創建視覺化結果顯示
const numbersContainer = document.createElement('div');
numbersContainer.className = 'result-numbers';
numbers.forEach(num => {
const span = document.createElement('span');
span.className = 'result-number';
span.textContent = num;
numbersContainer.appendChild(span);
});
resultText.innerHTML = '';
resultText.appendChild(numbersContainer);
result.classList.add('has-result');
// 📝 儲存結果
this.lastResult = `${this.translations[this.currentLanguage].numberGen} (${minValue}-${maxValue}): ${numbers.join(', ')}`;
this.addToHistory(this.lastResult);
// 🔓 重新啟用按鈕
generateBtn.disabled = false;
console.log(`🔢 自訂生成結果: ${numbers.join(', ')}`);
}, 500); // 0.5秒延遲
}
🎨 音效系統與視覺特效
說明:Web Audio API 音效系統和 CSS 動畫特效的完整實作,為不同的隨機生成操作提供豐富的聽覺和視覺回饋,大幅提升使用者體驗。
🎯 主要功能:
- 動態音效:振盪器生成不同頻率的音效回饋
- 音效分類:硬幣和骰子操作有不同的音效特色
- 錯誤處理:優雅處理音效 API 不支援的情況
- 視覺動畫:硬幣翻轉和骰子滾動的流暢動畫
// 🎵 音效系統初始化
initAudio() {
try {
// 🎛️ 嘗試創建 Web Audio 上下文
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
console.log('✅ Web Audio API 初始化成功');
} catch (e) {
// 🚫 優雅處理不支援的瀏覽器
console.log('❌ Web Audio API 不支援,音效功能將被停用');
this.audioContext = null;
}
}
// 🔊 動態音效播放方法
playSound(type) {
// 🛡️ 檢查音效系統可用性
if (!this.audioContext) {
console.log('🔇 音效系統不可用,跳過播放');
return;
}
// 🎛️ 創建音效組件
const oscillator = this.audioContext.createOscillator(); // 振盪器
const gainNode = this.audioContext.createGain(); // 音量控制
// 🔗 連接音效鏈
oscillator.connect(gainNode);
gainNode.connect(this.audioContext.destination);
// 🎯 根據操作類型設定不同音效
if (type === 'coin') {
// 🪙 硬幣音效:高頻到低頻的金屬聲
oscillator.frequency.setValueAtTime(800, this.audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(400, this.audioContext.currentTime + 0.3);
// 🎚️ 音量漸變效果
gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.3);
console.log('🪙 播放硬幣音效');
} else if (type === 'dice') {
// 🎲 骰子音效:中頻的滾動聲
oscillator.frequency.setValueAtTime(600, this.audioContext.currentTime);
oscillator.frequency.exponentialRampToValueAtTime(300, this.audioContext.currentTime + 0.2);
// 🎚️ 較短的音效持續時間
gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.2);
console.log('🎲 播放骰子音效');
}
// ▶️ 播放音效
oscillator.start();
oscillator.stop(this.audioContext.currentTime + 0.3);
}
// 🎭 CSS 動畫類別管理
toggleAnimation(element, animationClass, duration = 2000) {
// ➕ 添加動畫類別
element.classList.add(animationClass);
// ⏰ 動畫完成後自動移除類別
setTimeout(() => {
element.classList.remove(animationClass);
}, duration);
console.log(`🎬 啟動動畫: ${animationClass} (${duration}ms)`);
}
🛠️ 歷史記錄管理系統
說明:完整的歷史記錄管理系統,包含本地存儲、記錄限制、時間戳記、複製分享、清除功能等實用工具方法,提供完整的操作追蹤能力。
🎯 主要功能:
- 持久化存儲:使用 LocalStorage 保存歷史記錄
- 智能限制:自動限制歷史記錄數量避免過度佔用
- 時間追蹤:為每個記錄添加精確的時間戳記
- 互動功能:複製、分享、清除等完整功能
// 📝 歷史記錄新增方法
addToHistory(result) {
// 🕐 生成時間戳記(根據當前語言格式化)
const timestamp = new Date().toLocaleString(
this.currentLanguage === 'zh' ? 'zh-TW' : 'en-US'
);
// ➕ 將新記錄添加到陣列開頭
this.history.unshift({
result: result,
timestamp: timestamp
});
// 🔢 限制歷史記錄數量(最多保留50筆)
if (this.history.length > 50) {
this.history = this.history.slice(0, 50);
console.log('📋 歷史記錄已裁剪至50筆');
}
// 💾 保存到 LocalStorage
try {
localStorage.setItem('rng-history', JSON.stringify(this.history));
console.log(`📝 新增歷史記錄: ${result}`);
} catch (e) {
console.error('❌ 保存歷史記錄失敗:', e);
}
// 🔄 更新顯示
this.updateHistoryDisplay();
}
// 🖥️ 歷史記錄顯示更新
updateHistoryDisplay() {
const historyList = document.getElementById('history-list');
if (!historyList) return;
// 🧹 清空現有內容
historyList.innerHTML = '';
// 📄 只顯示最新的10筆記錄
const recentHistory = this.history.slice(0, 10);
recentHistory.forEach((item, index) => {
const div = document.createElement('div');
div.className = 'history-item';
// 🎨 創建豐富的歷史項目內容
div.innerHTML = `
${item.result}
${item.timestamp}
`;
historyList.appendChild(div);
});
console.log(`🔄 歷史顯示已更新: ${recentHistory.length} 筆記錄`);
}
// 📋 複製結果功能
copyResult() {
if (!this.lastResult) {
alert(this.translations[this.currentLanguage].noResultToCopy);
return;
}
// 🔄 嘗試現代剪貼簿 API
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(this.lastResult).then(() => {
alert(this.translations[this.currentLanguage].copied);
console.log('📋 使用現代 API 複製成功');
}).catch((err) => {
// 🔄 降級到傳統方法
this.fallbackCopy(this.lastResult);
});
} else {
// 🔄 直接使用傳統方法
this.fallbackCopy(this.lastResult);
}
}
// 🔄 備用複製方法(支援舊瀏覽器)
fallbackCopy(text) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
alert(this.translations[this.currentLanguage].copied);
console.log('📋 使用備用方法複製成功');
} else {
console.error('❌ 備用複製方法失敗');
}
} catch (err) {
console.error('❌ 複製操作失敗:', err);
}
document.body.removeChild(textArea);
}
// 📤 分享結果功能
shareResult() {
if (!this.lastResult) {
alert(this.translations[this.currentLanguage].noResultToShare);
return;
}
// 🔄 嘗試現代分享 API
if (navigator.share) {
navigator.share({
title: this.translations[this.currentLanguage].shareTitle,
text: this.lastResult,
url: window.location.href
}).then(() => {
console.log('📤 分享成功');
}).catch((err) => {
console.log('❌ 分享被取消或失敗:', err);
});
} else {
// 🔄 降級到複製功能
this.copyResult();
alert(this.translations[this.currentLanguage].shared);
console.log('📤 降級到複製功能');
}
}
// 👁️ 歷史面板顯示切換
toggleHistory() {
const panel = document.getElementById('history-panel');
const btn = document.getElementById('history-btn');
if (!panel || !btn) return;
if (panel.style.display === 'none' || panel.style.display === '') {
// 🔍 顯示歷史面板
panel.style.display = 'block';
btn.textContent = this.translations[this.currentLanguage].hideHistory;
this.updateHistoryDisplay();
console.log('👁️ 顯示歷史面板');
} else {
// 🙈 隱藏歷史面板
panel.style.display = 'none';
btn.textContent = this.translations[this.currentLanguage].showHistory;
console.log('🙈 隱藏歷史面板');
}
}
// 🗑️ 清除歷史記錄
clearHistory() {
// ⚠️ 確認對話框
if (confirm(this.translations[this.currentLanguage].confirmClearHistory)) {
// 🧹 清空記錄
this.history = [];
// 💾 更新 LocalStorage
try {
localStorage.removeItem('rng-history');
console.log('🗑️ LocalStorage 歷史記錄已清除');
} catch (e) {
console.error('❌ 清除 LocalStorage 失敗:', e);
}
// 🔄 更新顯示
this.updateHistoryDisplay();
// ✅ 確認訊息
alert(this.translations[this.currentLanguage].historyCleared);
console.log('✅ 歷史記錄清除完成');
}
}
// 📋 複製歷史項目
copyHistoryItem(index) {
if (this.history[index]) {
const item = this.history[index].result;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(item).then(() => {
console.log(`📋 歷史項目 ${index + 1} 複製成功`);
});
} else {
this.fallbackCopy(item);
}
}
}
🚀 工具初始化與全域函數
說明:完整的工具初始化流程和全域函數定義,確保向後兼容性、錯誤處理和優雅的載入體驗。處理 DOM 準備就緒事件和全域變數管理。
🎯 主要功能:
- 初始化流程:DOM 載入完成後自動初始化工具
- 全域函數:為 HTML onclick 事件提供全域存取點
- 向後兼容:支援舊版本的函數調用方式
- 錯誤處理:優雅處理初始化失敗情況
// 🚀 工具初始化核心邏輯
// 全域變數聲明
let rng; // 隨機數生成器實例
// 🎯 DOM 準備就緒時自動初始化
document.addEventListener('DOMContentLoaded', () => {
try {
// 🏗️ 創建隨機數生成器實例
rng = new RandomNumberGenerator();
// ✅ 初始化成功日誌
console.log('🎲 隨機數生成器已初始化');
console.log('✨ 功能已就緒:擲硬幣、擲骰子、自訂範圍生成');
console.log('🎵 音效系統已啟用');
console.log('📜 歷史記錄系統已載入');
console.log('🌐 雙語系統已整合');
// 🔍 檢查必要的 DOM 元素
const requiredElements = [
'main-title', 'coin', 'dice-type', 'min-value', 'max-value'
];
const missingElements = requiredElements.filter(id => !document.getElementById(id));
if (missingElements.length > 0) {
console.warn('⚠️ 部分 DOM 元素缺失:', missingElements);
} else {
console.log('✅ 所有必要的 DOM 元素已確認存在');
}
// 🎯 設定初始狀態
const activeTab = document.querySelector('.rng-tab.active');
if (activeTab) {
console.log(`🎯 當前活動標籤: ${activeTab.dataset.tab}`);
}
// 📊 顯示歷史記錄統計
console.log(`📋 已載入歷史記錄: ${rng.history.length} 筆`);
} catch (error) {
// ❌ 初始化失敗處理
console.error('❌ 隨機數生成器初始化失敗:', error);
// 🔄 嘗試基本功能降級
console.log('🔄 嘗試啟用基本功能...');
// 基本的全域函數定義(無需類別實例)
window.flipCoin = () => {
console.log('🔄 降級模式:基本擲硬幣功能');
alert(Math.random() < 0.5 ? '正面' : '反面');
};
window.rollDice = () => {
console.log('🔄 降級模式:基本擲骰子功能');
const result = Math.floor(Math.random() * 6) + 1;
alert(`骰子結果: ${result}`);
};
}
});
// 🌐 全域函數定義(用於 HTML onclick 事件)
// 這些函數提供與 HTML 內嵌事件的相容性
// 🪙 擲硬幣全域函數
function flipCoin() {
if (rng && typeof rng.flipCoin === 'function') {
rng.flipCoin();
} else {
console.error('❌ 隨機數生成器未初始化或方法不存在');
// 🔄 降級處理
const result = Math.random() < 0.5 ? '正面' : '反面';
alert(`硬幣結果: ${result}`);
}
}
// 🎲 擲骰子全域函數
function rollDice() {
if (rng && typeof rng.rollDice === 'function') {
rng.rollDice();
} else {
console.error('❌ 隨機數生成器未初始化或方法不存在');
// 🔄 降級處理
const result = Math.floor(Math.random() * 6) + 1;
alert(`骰子結果: ${result}`);
}
}
// 🔢 自訂範圍生成全域函數
function generateNumbers() {
if (rng && typeof rng.generateNumbers === 'function') {
rng.generateNumbers();
} else {
console.error('❌ 隨機數生成器未初始化或方法不存在');
// 🔄 降級處理
const min = 1, max = 100;
const result = Math.floor(Math.random() * (max - min + 1)) + min;
alert(`隨機數: ${result}`);
}
}
// 📋 複製結果全域函數
function copyResult() {
if (rng && typeof rng.copyResult === 'function') {
rng.copyResult();
} else {
console.error('❌ 隨機數生成器未初始化或複製功能不可用');
alert('複製功能暫時不可用');
}
}
// 📤 分享結果全域函數
function shareResult() {
if (rng && typeof rng.shareResult === 'function') {
rng.shareResult();
} else {
console.error('❌ 隨機數生成器未初始化或分享功能不可用');
alert('分享功能暫時不可用');
}
}
// 📜 切換歷史記錄全域函數
function toggleHistory() {
if (rng && typeof rng.toggleHistory === 'function') {
rng.toggleHistory();
} else {
console.error('❌ 隨機數生成器未初始化或歷史功能不可用');
alert('歷史記錄功能暫時不可用');
}
}
// 🗑️ 清除歷史記錄全域函數
function clearHistory() {
if (rng && typeof rng.clearHistory === 'function') {
rng.clearHistory();
} else {
console.error('❌ 隨機數生成器未初始化或清除功能不可用');
alert('清除功能暫時不可用');
}
}
// 🔧 除錯和診斷工具(開發環境用)
if (typeof window !== 'undefined') {
// 🛠️ 提供全域除錯接口
window.rngDebug = {
// 📊 獲取當前狀態
getStatus() {
if (!rng) return { status: 'not_initialized' };
return {
status: 'initialized',
currentLanguage: rng.currentLanguage,
historyCount: rng.history ? rng.history.length : 0,
lastResult: rng.lastResult || 'none',
audioAvailable: !!rng.audioContext
};
},
// 🔄 強制重新初始化
reinitialize() {
try {
rng = new RandomNumberGenerator();
console.log('🔄 隨機數生成器已重新初始化');
return true;
} catch (error) {
console.error('❌ 重新初始化失敗:', error);
return false;
}
},
// 🧪 測試所有功能
testAllFeatures() {
console.log('🧪 開始功能測試...');
const tests = [
{ name: '擲硬幣', fn: () => flipCoin() },
{ name: '擲骰子', fn: () => rollDice() },
{ name: '自訂生成', fn: () => generateNumbers() },
{ name: '歷史切換', fn: () => toggleHistory() }
];
tests.forEach(test => {
try {
console.log(`🔍 測試: ${test.name}`);
test.fn();
console.log(`✅ ${test.name} 測試通過`);
} catch (error) {
console.error(`❌ ${test.name} 測試失敗:`, error);
}
});
console.log('🧪 功能測試完成');
}
};
// 💡 開發提示
console.log('💡 開發提示: 使用 window.rngDebug.getStatus() 查看狀態');
console.log('💡 開發提示: 使用 window.rngDebug.testAllFeatures() 測試功能');
}
效能優化
核心效能策略
Core Performance Strategies
- 事件代理:使用事件代理減少記憶體佔用
- 防抖處理:避免頻繁的 DOM 操作和計算
- 記憶體管理:及時清理音效資源和事件監聽器
- 本地存儲優化:限制歷史記錄數量避免過度佔用
- 動畫優化:使用 CSS3 硬體加速提升動畫流暢度
安全性考量
資料安全
Data Security
- 本地處理:所有隨機數生成完全在客戶端進行
- 無網路傳輸:不向任何伺服器傳送使用者資料
- 輸入驗證:嚴格驗證所有使用者輸入參數
- 錯誤處理:優雅處理異常情況,不洩露系統資訊
瀏覽器兼容性
支援範圍
Support Range
瀏覽器 | 最低版本 | 音效支援 | 完整功能 |
---|---|---|---|
Chrome | 60+ | ✅ 完整支援 | ✅ 完整支援 |
Firefox | 55+ | ✅ 完整支援 | ✅ 完整支援 |
Safari | 12+ | ⚠️ 部分限制 | ✅ 完整支援 |
Edge | 79+ | ✅ 完整支援 | ✅ 完整支援 |
未來改進方向
- 進階隨機模式:加權隨機、正態分佈等統計學功能
- 自訂音效:允許使用者上傳自己的音效檔案
- 視覺主題:提供多種視覺主題和自訂選項
- 分享功能增強:支援更多社交平台和格式
- 統計分析:提供詳細的隨機數統計和分析功能
總結
隨機數生成器展示了現代 Web 應用開發的完整技術棧,從基礎的 DOM 操作到進階的音效處理, 從本地存儲管理到國際化支援,每個環節都經過精心設計和優化。 這個工具不僅提供了實用的隨機數生成功能,更重要的是演示了如何構建一個 使用者友好、功能完整、技術先進的純前端應用。