隨機數生成器技術實作

深入了解多功能隨機數生成器的完整實作,包含擲硬幣、擲骰子、自訂範圍生成、音效系統、歷史記錄管理和雙語系統整合

概述

隨機數生成器是一個功能豐富的線上工具,專為遊戲、決策、抽籤等場景設計,能夠提供多種隨機模式的專業生成功能。 本工具採用純前端架構,完全在瀏覽器端運行,零網路傳輸,確保數據的絕對隱私和安全性。 提供擲硬幣、擲骰子、自訂範圍生成、音效回饋、歷史記錄管理、雙語系統等專業功能。

🔒 隱私保護承諾

所有隨機數生成處理都在您的瀏覽器本地進行,數據不會上傳到任何伺服器,確保您的使用記錄完全安全。

技術架構與核心設計

整體架構設計

技術項目 實作方式 設計考量
隨機數生成 Math.random() + 安全性增強 跨平台兼容性,真隨機性
音效系統 Web Audio API + 振盪器 即時音效回饋,使用者體驗
視覺動畫 CSS3 動畫 + JavaScript 流暢動畫效果,視覺回饋
歷史管理 LocalStorage + JSON 持久化存儲,快速存取
雙語系統 全域事件 + 本地翻譯 實時切換,完整國際化

核心算法特色

  • 多模式生成:擲硬幣、擲骰子、自訂範圍三種主要模式
  • 音效整合:Web Audio API 實現的動態音效系統
  • 視覺回饋:硬幣翻轉和骰子滾動的真實動畫效果
  • 歷史追蹤:完整的操作記錄和時間戳記系統
  • 參數驗證:輸入範圍檢查和錯誤處理機制
  • 響應式設計:支援桌面、平板、手機多種設備

關鍵功能與特色

🪙 擲硬幣模式

經典的正反面選擇,配有硬幣翻轉動畫效果和音效回饋

🎲 擲骰子模式

支援 D4-D100 多種骰子類型,可同時擲多顆骰子

🔢 自訂範圍模式

靈活設定最小值、最大值、數量,支援重複/不重複選項

🎵 音效系統

Web Audio API 實現的即時音效,為不同操作提供聽覺回饋

📜 歷史記錄

自動記錄所有操作結果,支援查看、複製、清除功能

🌐 雙語系統

完整的中英文支援,實時語言切換不影響操作流程

實作細節

以下是完整程式碼實作,按功能模組分類展示。點擊卡片標題可展開查看詳細程式碼:

📦 核心隨機數生成器類別

說明: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() 測試功能');
}

效能優化

核心效能策略

  • 事件代理:使用事件代理減少記憶體佔用
  • 防抖處理:避免頻繁的 DOM 操作和計算
  • 記憶體管理:及時清理音效資源和事件監聽器
  • 本地存儲優化:限制歷史記錄數量避免過度佔用
  • 動畫優化:使用 CSS3 硬體加速提升動畫流暢度

安全性考量

資料安全

  • 本地處理:所有隨機數生成完全在客戶端進行
  • 無網路傳輸:不向任何伺服器傳送使用者資料
  • 輸入驗證:嚴格驗證所有使用者輸入參數
  • 錯誤處理:優雅處理異常情況,不洩露系統資訊

瀏覽器兼容性

支援範圍

瀏覽器 最低版本 音效支援 完整功能
Chrome 60+ ✅ 完整支援 ✅ 完整支援
Firefox 55+ ✅ 完整支援 ✅ 完整支援
Safari 12+ ⚠️ 部分限制 ✅ 完整支援
Edge 79+ ✅ 完整支援 ✅ 完整支援

未來改進方向

  • 進階隨機模式:加權隨機、正態分佈等統計學功能
  • 自訂音效:允許使用者上傳自己的音效檔案
  • 視覺主題:提供多種視覺主題和自訂選項
  • 分享功能增強:支援更多社交平台和格式
  • 統計分析:提供詳細的隨機數統計和分析功能

總結

隨機數生成器展示了現代 Web 應用開發的完整技術棧,從基礎的 DOM 操作到進階的音效處理, 從本地存儲管理到國際化支援,每個環節都經過精心設計和優化。 這個工具不僅提供了實用的隨機數生成功能,更重要的是演示了如何構建一個 使用者友好、功能完整、技術先進的純前端應用。