貸款計算器技術實作

深入了解貸款計算器的完整實作,包含等額本息與等額本金計算、攤還明細生成、CSV匯出功能、多頻率支援和雙語界面整合

概述

密碼產生器是一個專業的安全工具,專為創建高強度密碼而設計。支援自定義字符集、批次生成、即時強度評估和多格式導出。 採用 Web Crypto API 的加密級隨機數生成,確保密碼的安全性和不可預測性。 提供單一模式和批次模式兩種操作方式,滿足個人和企業級需求。

🔒 加密級安全保證

使用 Web Crypto API 的 crypto.getRandomValues() 生成加密級隨機數,確保密碼具有最高級別的安全性和隨機性。

技術架構與核心設計

整體架構設計

技術項目 實作方式 設計考量
隨機數生成 Web Crypto API (crypto.getRandomValues) 加密級安全性,符合國際標準
密碼評估 多因子評分系統 長度、字符多樣性、模式檢查
字符集管理 可配置字符集組合 靈活性與安全性平衡
批次處理 高效能迴圈生成 支援最多1000筆密碼
導出功能 TXT/CSV 多格式下載 企業級資料管理需求

核心類別架構

class PasswordGenerator {
    constructor() {
        this.mode = 'single';                // 'single' 或 'batch'
        this.passwords = [];                 // 批次密碼儲存
        this.currentLanguage = 'zh';         // 當前語言
        this.maxFiles = 1000;               // 最大批次數量
        this.supportedCharsets = {
            uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
            lowercase: 'abcdefghijklmnopqrstuvwxyz', 
            numbers: '0123456789',
            symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?'
        };
        this.init();
    }
    
    init() {
        this.setupGlobalLanguageListener();  // 必須最先執行
        this.bindEvents();
        this.updateLanguage();
        this.updateStrengthMeter();
    }
}

關鍵功能實現

  • 🔐 加密級隨機生成:使用 Web Crypto API 確保密碼的不可預測性
  • ⚙️ 自定義字符集:支援大寫、小寫、數字、特殊符號的靈活組合
  • 📊 即時強度評估:多因子評分系統提供即時密碼強度分析
  • 🔄 雙操作模式:單一密碼生成和批次密碼生成
  • 📈 視覺化強度指示:彩色進度條和詳細評分顯示
  • 📋 一鍵複製:支援單一密碼和批次密碼的快速複製
  • 💾 多格式導出:TXT 和 CSV 格式下載,適合不同用途
  • 🌐 完整雙語支援:中英文介面無縫切換

⚠️ 安全建議

建議使用至少12字符長度,並包含多種字符類型。定期更換重要帳戶密碼,避免在多個網站使用相同密碼。

完整程式碼實作

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

📦 核心密碼產生器類別

密碼產生器的核心類別實作,包含完整的建構函數、屬性定義、雙語翻譯系統和基本初始化流程。 這個類別是整個密碼產生系統的基礎,負責管理所有狀態和配置。

class PasswordGenerator {
    constructor() {
        // 基本狀態管理 / Basic state management
        this.mode = 'single';              // 操作模式:'single' 或 'batch'
        this.passwords = [];               // 批次密碼儲存陣列
        this.currentLanguage = 'zh';       // 當前語言設定
        this.maxFiles = 1000;             // 最大批次生成數量限制
        
        // 完整的雙語翻譯字典 / Complete bilingual translation dictionary
        this.translations = {
            zh: {
                title: '🔒 密碼產生器',
                modeToggleBatch: '切換至批次模式',
                modeToggleSingle: '切換至單一模式',
                passwordSettings: '🔧 密碼設定',
                passwordLength: '密碼長度',
                passwordElements: '密碼組成元素',
                uppercase: '大寫字母 (A-Z)',
                lowercase: '小寫字母 (a-z)',
                numbers: '數字 (0-9)',
                symbols: '特殊符號 (!@#$%^&*)',
                generatePassword: '🎲 產生密碼',
                generatedPassword: '產生的密碼',
                copyBtn: '複製',
                copiedBtn: '已複製!',
                passwordPlaceholder: '點擊「產生密碼」來生成您的安全密碼',
                batchTitle: '📋 批次密碼產生',
                batchCount: '產生數量',
                batchUnit: '筆密碼',
                batchGenerate: '🎲 批次產生',
                copyAll: '📋 複製全部',
                downloadTxt: '📄 下載 TXT',
                downloadCsv: '📊 下載 CSV',
                batchList: '批次密碼列表',
                noPasswordsGenerated: '尚未產生任何密碼',
                passwordStrength: '密碼強度',
                weak: '弱',
                medium: '中等',
                strong: '強',
                alertCharType: '請至少選擇一種字符類型!',
                alertBatchRange: '產生數量必須介於 1 到 1000 之間!',
                csvHeader: '編號,密碼'
            },
            en: {
                title: '🔒 Password Generator',
                modeToggleBatch: 'Switch to Batch Mode',
                modeToggleSingle: 'Switch to Single Mode',
                passwordSettings: '🔧 Password Settings',
                passwordLength: 'Password Length',
                passwordElements: 'Password Components',
                uppercase: 'Uppercase Letters (A-Z)',
                lowercase: 'Lowercase Letters (a-z)',
                numbers: 'Numbers (0-9)',
                symbols: 'Special Symbols (!@#$%^&*)',
                generatePassword: '🎲 Generate Password',
                generatedPassword: 'Generated Password',
                copyBtn: 'Copy',
                copiedBtn: 'Copied!',
                passwordPlaceholder: 'Click "Generate Password" to create your secure password',
                batchTitle: '📋 Batch Password Generation',
                batchCount: 'Generate Quantity',
                batchUnit: 'passwords',
                batchGenerate: '🎲 Batch Generate',
                copyAll: '📋 Copy All',
                downloadTxt: '📄 Download TXT',
                downloadCsv: '📊 Download CSV',
                batchList: 'Batch Password List',
                noPasswordsGenerated: 'No passwords generated yet',
                passwordStrength: 'Password Strength',
                weak: 'Weak',
                medium: 'Medium',
                strong: 'Strong',
                alertCharType: 'Please select at least one character type!',
                alertBatchRange: 'Generation quantity must be between 1 and 1000!',
                csvHeader: 'No.,Password'
            }
        };
        
        // 初始化工具 / Initialize tool
        this.init();
    }
    
    /**
     * 工具初始化流程 / Tool initialization process
     * 按順序執行:語言監聽器 → 事件綁定 → 語言更新 → 強度計量器
     */
    init() {
        this.setupGlobalLanguageListener();  // 必須最先執行
        this.bindEvents();                   // 綁定所有事件監聽器
        this.updateLanguage();               // 更新介面語言
        this.updateStrengthMeter();          // 初始化密碼強度顯示
    }
}

🌐 全域語言系統整合

實現與 Tool Master 全域語言系統的完美整合,包含語言切換監聽器、時序處理和語言同步機制。 確保工具能夠響應全站的語言切換事件,並正確處理初始化時序問題。

/**
 * 全域語言系統整合 / Global Language System Integration
 * 處理與 Tool Master 主站語言系統的雙向通信
 */
setupGlobalLanguageListener() {
    // 監聽全域語言切換事件 / Listen for global language change events
    window.addEventListener('languageChanged', (event) => {
        this.currentLanguage = event.detail.language;
        this.updateLanguage();
        console.log(`密碼產生器語言已切換至: ${this.currentLanguage}`);
    });
    
    // 處理全域語言系統加載時序問題 / Handle global language system loading timing
    const checkGlobalLanguage = () => {
        if (window.globalI18n) {
            // 同步當前語言設定 / Sync current language setting
            this.currentLanguage = window.globalI18n.currentLanguage;
            this.updateLanguage();
            console.log(`同步全域語言設定: ${this.currentLanguage}`);
            return true;
        }
        return false;
    };
    
    // 立即檢查,如果沒有就延遲重試 / Immediate check, retry if not available
    if (!checkGlobalLanguage()) {
        setTimeout(() => {
            checkGlobalLanguage();
        }, 100);
    }
}

/**
 * 完整的語言更新方法 / Complete language update method
 * 更新所有介面元素的文字內容,確保無遺漏
 */
updateLanguage() {
    const t = this.translations[this.currentLanguage];
    
    // 更新主要標題 / Update main title
    const title = document.querySelector('.password-generator-standalone h1');
    if (title) title.textContent = t.title;
    
    // 更新模式切換按鈕 / Update mode toggle button
    const modeToggle = document.getElementById('modeToggle');
    if (modeToggle) {
        modeToggle.textContent = this.mode === 'single' ? t.modeToggleBatch : t.modeToggleSingle;
    }
    
    // 更新密碼設定區塊標題 / Update password settings section title
    const singleTitle = document.querySelector('#singleMode h2');
    if (singleTitle) singleTitle.textContent = t.passwordSettings;
    
    // 更新密碼長度標籤 / Update password length label
    const lengthLabel = document.querySelector('label[for="passwordLength"]');
    if (lengthLabel) lengthLabel.textContent = t.passwordLength;
    
    // 更新密碼組成元素標籤 / Update password components label
    const controlGroups = document.querySelectorAll('.control-group');
    controlGroups.forEach(group => {
        const label = group.querySelector('label');
        if (label && !label.getAttribute('for') && 
            (label.textContent === '密碼組成元素' || label.textContent === 'Password Components')) {
            label.textContent = t.passwordElements;
        }
    });
    
    // 更新字符類型選項標籤 / Update character type option labels
    const uppercaseLabel = document.querySelector('label[for="includeUppercase"]');
    if (uppercaseLabel) uppercaseLabel.textContent = t.uppercase;
    
    const lowercaseLabel = document.querySelector('label[for="includeLowercase"]');
    if (lowercaseLabel) lowercaseLabel.textContent = t.lowercase;
    
    const numbersLabel = document.querySelector('label[for="includeNumbers"]');
    if (numbersLabel) numbersLabel.textContent = t.numbers;
    
    const symbolsLabel = document.querySelector('label[for="includeSymbols"]');
    if (symbolsLabel) symbolsLabel.textContent = t.symbols;
    
    // 更新所有按鈕文字 / Update all button texts
    this.updateButtons(t);
    
    // 更新批次模式介面 / Update batch mode interface
    this.updateBatchModeLanguage(t);
    
    // 更新密碼強度顯示 / Update password strength display
    this.updatePasswordStrengthLanguage(t);
}

/**
 * 更新按鈕文字的輔助方法 / Helper method to update button texts
 */
updateButtons(t) {
    const generateBtn = document.getElementById('generateBtn');
    if (generateBtn) generateBtn.textContent = t.generatePassword;
    
    const copyBtn = document.getElementById('copyBtn');
    if (copyBtn && !copyBtn.textContent.includes('已複製') && !copyBtn.textContent.includes('Copied')) {
        copyBtn.textContent = t.copyBtn;
    }
    
    const batchGenerateBtn = document.getElementById('batchGenerateBtn');
    if (batchGenerateBtn) batchGenerateBtn.textContent = t.batchGenerate;
    
    const copyAllBtn = document.getElementById('copyAllBtn');
    if (copyAllBtn) copyAllBtn.textContent = t.copyAll;
    
    const downloadTxtBtn = document.getElementById('downloadTxtBtn');
    if (downloadTxtBtn) downloadTxtBtn.textContent = t.downloadTxt;
    
    const downloadCsvBtn = document.getElementById('downloadCsvBtn');
    if (downloadCsvBtn) downloadCsvBtn.textContent = t.downloadCsv;
}

🎯 事件綁定與DOM初始化

完整的事件監聽器設定,包含模式切換、密碼生成、複製功能、批次操作和下載功能。 實現雙向數據綁定,確保 UI 和數據狀態的完美同步。

/**
 * 事件綁定與DOM初始化 / Event Binding & DOM Initialization
 * 設置所有必要的事件監聽器,實現完整的用戶互動功能
 */
bindEvents() {
    // 模式切換事件 / Mode switching event
    const modeToggleBtn = document.getElementById('modeToggle');
    if (modeToggleBtn) {
        modeToggleBtn.addEventListener('click', () => {
            this.toggleMode();
        });
    }
    
    // 密碼長度雙向同步 / Password length two-way sync
    const passwordLengthSlider = document.getElementById('passwordLength');
    const passwordLengthNumber = document.getElementById('passwordLengthNum');
    
    if (passwordLengthSlider) {
        passwordLengthSlider.addEventListener('input', (e) => {
            if (passwordLengthNumber) {
                passwordLengthNumber.value = e.target.value;
            }
            this.updateStrengthMeter(); // 即時更新強度指示器
        });
    }
    
    if (passwordLengthNumber) {
        passwordLengthNumber.addEventListener('input', (e) => {
            if (passwordLengthSlider) {
                passwordLengthSlider.value = e.target.value;
            }
            this.updateStrengthMeter(); // 即時更新強度指示器
        });
    }
    
    // 字符選項變化監聽 / Character option change listeners
    const characterOptions = ['includeUppercase', 'includeLowercase', 'includeNumbers', 'includeSymbols'];
    characterOptions.forEach(optionId => {
        const checkbox = document.getElementById(optionId);
        if (checkbox) {
            checkbox.addEventListener('change', () => {
                this.updateStrengthMeter(); // 字符選項變化時更新強度評估
            });
        }
    });
    
    // 單一密碼生成 / Single password generation
    const generateBtn = document.getElementById('generateBtn');
    if (generateBtn) {
        generateBtn.addEventListener('click', () => {
            this.generateSinglePassword();
        });
    }
    
    // 單一密碼複製 / Single password copy
    const copyBtn = document.getElementById('copyBtn');
    if (copyBtn) {
        copyBtn.addEventListener('click', () => {
            this.copyPassword();
        });
    }
    
    // 批次密碼生成 / Batch password generation
    const batchGenerateBtn = document.getElementById('batchGenerateBtn');
    if (batchGenerateBtn) {
        batchGenerateBtn.addEventListener('click', () => {
            this.generateBatchPasswords();
        });
    }
    
    // 批次密碼複製全部 / Batch password copy all
    const copyAllBtn = document.getElementById('copyAllBtn');
    if (copyAllBtn) {
        copyAllBtn.addEventListener('click', () => {
            this.copyAllPasswords();
        });
    }
    
    // 下載功能事件 / Download functionality events
    this.bindDownloadEvents();
}

/**
 * 下載功能事件綁定 / Download functionality event binding
 * 處理 TXT 和 CSV 格式的批次密碼下載
 */
bindDownloadEvents() {
    const downloadTxtBtn = document.getElementById('downloadTxtBtn');
    if (downloadTxtBtn) {
        downloadTxtBtn.addEventListener('click', () => {
            this.downloadPasswords('txt');
        });
    }
    
    const downloadCsvBtn = document.getElementById('downloadCsvBtn');
    if (downloadCsvBtn) {
        downloadCsvBtn.addEventListener('click', () => {
            this.downloadPasswords('csv');
        });
    }
}

/**
 * 模式切換功能 / Mode switching functionality
 * 在單一模式和批次模式之間切換,包含 UI 更新
 */
toggleMode() {
    const modeToggle = document.getElementById('modeToggle');
    const singleMode = document.getElementById('singleMode');
    const batchMode = document.getElementById('batchMode');
    const t = this.translations[this.currentLanguage];
    
    if (!modeToggle || !singleMode || !batchMode) {
        console.error('模式切換: 找不到必要的 DOM 元素');
        return;
    }
    
    if (this.mode === 'single') {
        // 切換到批次模式 / Switch to batch mode
        this.mode = 'batch';
        modeToggle.textContent = t.modeToggleSingle;
        singleMode.style.display = 'none';
        batchMode.classList.add('active');
        console.log('已切換到批次模式');
    } else {
        // 切換到單一模式 / Switch to single mode  
        this.mode = 'single';
        modeToggle.textContent = t.modeToggleBatch;
        singleMode.style.display = 'block';
        batchMode.classList.remove('active');
        console.log('已切換到單一模式');
    }
}

⚙️ 密碼生成核心引擎

密碼生成的核心算法實作,使用 Web Crypto API 的加密級隨機數生成。 包含字符集組合、安全隨機生成、單一和批次模式的完整實現。

/**
 * 字符集獲取與組合 / Character set retrieval and combination
 * 根據用戶選擇動態組合可用字符集
 */
getCharacterSet() {
    let charset = '';
    
    // 檢查大寫字母選項 / Check uppercase letters option
    if (document.getElementById('includeUppercase')?.checked) {
        charset += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    }
    
    // 檢查小寫字母選項 / Check lowercase letters option  
    if (document.getElementById('includeLowercase')?.checked) {
        charset += 'abcdefghijklmnopqrstuvwxyz';
    }
    
    // 檢查數字選項 / Check numbers option
    if (document.getElementById('includeNumbers')?.checked) {
        charset += '0123456789';
    }
    
    // 檢查特殊符號選項 / Check special symbols option
    if (document.getElementById('includeSymbols')?.checked) {
        charset += '!@#$%^&*()_+-=[]{}|;:,.<>?';
    }
    
    return charset;
}

/**
 * 加密級安全密碼生成 / Cryptographic-grade secure password generation
 * 使用 Web Crypto API 確保真正的隨機性和安全性
 */
generatePassword(length, charset) {
    // 驗證參數有效性 / Validate parameter validity
    if (!charset || charset.length === 0) {
        console.error('字符集為空,無法生成密碼');
        return '';
    }
    
    if (length < 1 || length > 128) {
        console.error('密碼長度必須在 1-128 之間');
        return '';
    }
    
    let password = '';
    
    try {
        // 使用 Web Crypto API 生成加密級隨機數 / Use Web Crypto API for cryptographic random numbers
        const array = new Uint32Array(length);
        crypto.getRandomValues(array);
        
        // 將隨機數映射到字符集 / Map random numbers to character set
        for (let i = 0; i < length; i++) {
            const randomIndex = array[i] % charset.length;
            password += charset[randomIndex];
        }
        
        console.log(`成功生成 ${length} 字符密碼,使用字符集長度: ${charset.length}`);
        
    } catch (error) {
        console.error('密碼生成失敗:', error);
        // 備用方案:使用 Math.random() (較不安全)
        for (let i = 0; i < length; i++) {
            const randomIndex = Math.floor(Math.random() * charset.length);
            password += charset[randomIndex];
        }
        console.warn('已降級使用 Math.random() 生成密碼');
    }
    
    return password;
}

/**
 * 單一密碼生成功能 / Single password generation functionality
 * 處理單一模式下的密碼生成和顯示
 */
generateSinglePassword() {
    const lengthInput = document.getElementById('passwordLength');
    const length = lengthInput ? parseInt(lengthInput.value) : 12;
    const charset = this.getCharacterSet();
    const t = this.translations[this.currentLanguage];
    
    // 驗證字符集選擇 / Validate character set selection
    if (!charset) {
        alert(t.alertCharType);
        return;
    }
    
    // 生成密碼 / Generate password
    const password = this.generatePassword(length, charset);
    if (!password) {
        console.error('密碼生成失敗');
        return;
    }
    
    // 更新顯示介面 / Update display interface
    const display = document.getElementById('passwordDisplay');
    const copyBtn = document.getElementById('copyBtn');
    
    if (display) {
        display.textContent = password;
        display.classList.remove('empty');
    }
    
    if (copyBtn) {
        copyBtn.style.display = 'block';
    }
    
    // 更新密碼強度指示器 / Update password strength indicator
    this.updateStrengthMeter(password);
    
    console.log(`單一密碼生成完成: 長度 ${length}, 強度評估已更新`);
}

/**
 * 批次密碼生成功能 / Batch password generation functionality
 * 處理批次模式下的大量密碼生成
 */
generateBatchPasswords() {
    const countInput = document.getElementById('batchCount');
    const lengthInput = document.getElementById('passwordLength');
    
    const count = countInput ? parseInt(countInput.value) : 10;
    const length = lengthInput ? parseInt(lengthInput.value) : 12;
    const charset = this.getCharacterSet();
    const t = this.translations[this.currentLanguage];
    
    // 驗證輸入參數 / Validate input parameters
    if (!charset) {
        alert(t.alertCharType);
        return;
    }
    
    if (count < 1 || count > 1000) {
        alert(t.alertBatchRange);
        return;
    }
    
    // 清空之前的密碼列表 / Clear previous password list
    this.passwords = [];
    
    // 批次生成密碼 / Batch generate passwords
    console.log(`開始批次生成 ${count} 個密碼,每個長度 ${length}`);
    const startTime = performance.now();
    
    for (let i = 0; i < count; i++) {
        const password = this.generatePassword(length, charset);
        if (password) {
            this.passwords.push(password);
        }
    }
    
    const endTime = performance.now();
    console.log(`批次生成完成,耗時 ${(endTime - startTime).toFixed(2)}ms`);
    
    // 更新顯示和啟用功能按鈕 / Update display and enable function buttons
    this.displayBatchPasswords();
    this.showBatchButtons();
}

🎨 密碼強度評估系統

多因子密碼強度評估算法,包含長度評分、字符多樣性分析、視覺化強度指示器和即時反饋系統。 提供弱、中等、強三級評估,幫助用戶創建更安全的密碼。

/**
 * 密碼強度計算引擎 / Password strength calculation engine
 * 基於多個因素的綜合評分算法
 */
calculateStrength(password) {
    if (!password || password.length === 0) {
        return { score: 0, text: '', class: 'weak' };
    }
    
    let score = 0;
    const feedback = [];
    
    // 長度評分 (最多 75 分) / Length scoring (max 75 points)
    if (password.length >= 8) {
        score += 25;
        feedback.push('長度達到基本要求');
    }
    if (password.length >= 12) {
        score += 25;
        feedback.push('長度達到推薦標準');
    }
    if (password.length >= 16) {
        score += 25;
        feedback.push('長度達到高安全標準');
    }
    
    // 字符類型多樣性評分 (最多 25 分) / Character type diversity scoring (max 25 points)
    let typeCount = 0;
    
    if (/[a-z]/.test(password)) {
        score += 6;
        typeCount++;
        feedback.push('包含小寫字母');
    }
    
    if (/[A-Z]/.test(password)) {
        score += 6;
        typeCount++;
        feedback.push('包含大寫字母');
    }
    
    if (/[0-9]/.test(password)) {
        score += 6;
        typeCount++;
        feedback.push('包含數字');
    }
    
    if (/[^A-Za-z0-9]/.test(password)) {
        score += 7;
        typeCount++;
        feedback.push('包含特殊符號');
    }
    
    // 字符類型多樣性獎勵 / Character type diversity bonus
    if (typeCount >= 3) {
        score += 5;
        feedback.push('字符類型豐富');
    }
    
    // 模式檢查 (扣分項目) / Pattern checking (penalty items)
    if (/(.)\1{2,}/.test(password)) {
        score -= 10;
        feedback.push('包含重複字符(扣分)');
    }
    
    if (/123|abc|qwe/i.test(password)) {
        score -= 15;
        feedback.push('包含常見序列(扣分)');
    }
    
    // 確保分數在合理範圍內 / Ensure score is within reasonable range
    score = Math.max(0, Math.min(100, score));
    
    // 評級判斷 / Rating determination
    const t = this.translations[this.currentLanguage];
    let strengthClass, strengthText;
    
    if (score < 30) {
        strengthClass = 'weak';
        strengthText = t.weak;
    } else if (score < 60) {
        strengthClass = 'medium';
        strengthText = t.medium;
    } else {
        strengthClass = 'strong';
        strengthText = t.strong;
    }
    
    console.log(`密碼強度評估: ${score}分 (${strengthText})`, feedback);
    
    return { 
        score, 
        text: strengthText, 
        class: strengthClass,
        feedback: feedback
    };
}

/**
 * 強度指示器更新 / Strength indicator update
 * 更新視覺化的強度進度條和文字顯示
 */
updateStrengthMeter(password = null) {
    const display = document.getElementById('passwordDisplay');
    const strengthBar = document.getElementById('strengthBar');
    const strengthText = document.getElementById('strengthText');
    
    // 如果沒有指定密碼且顯示區域為空,則清空強度指示器
    if (!password && display?.classList.contains('empty')) {
        if (strengthBar) {
            strengthBar.style.width = '0%';
            strengthBar.className = 'strength-bar';
        }
        if (strengthText) {
            strengthText.textContent = '';
            strengthText.className = 'strength-text';
        }
        return;
    }
    
    // 如果沒有指定密碼,則生成測試密碼進行評估
    const testPassword = password || this.generateTestPassword();
    if (!testPassword) return;
    
    // 計算強度 / Calculate strength
    const strength = this.calculateStrength(testPassword);
    const t = this.translations[this.currentLanguage];
    
    // 更新進度條 / Update progress bar
    if (strengthBar) {
        strengthBar.style.width = strength.score + '%';
        strengthBar.className = `strength-bar strength-${strength.class}`;
        
        // 添加平滑過渡動畫 / Add smooth transition animation
        strengthBar.style.transition = 'width 0.3s ease, background-color 0.3s ease';
    }
    
    // 更新文字顯示 / Update text display
    if (strengthText) {
        strengthText.textContent = `${t.passwordStrength}: ${strength.text} (${strength.score}%)`;
        strengthText.className = `strength-text strength-${strength.class}`;
    }
    
    console.log(`強度指示器已更新: ${strength.score}% (${strength.class})`);
}

/**
 * 生成測試密碼用於強度預覽 / Generate test password for strength preview
 * 用於在用戶調整設定時提供即時的強度預覽
 */
generateTestPassword() {
    const lengthInput = document.getElementById('passwordLength');
    const length = lengthInput ? parseInt(lengthInput.value) : 12;
    const charset = this.getCharacterSet();
    
    if (!charset) {
        return '';
    }
    
    // 生成簡化的測試密碼(不用於實際使用)
    return this.generatePassword(Math.min(length, 16), charset);
}

🛠️ 複製與下載功能

完整的複製功能和多格式下載系統,包含單一密碼複製、批次密碼複製、TXT/CSV格式導出。 使用 Clipboard API 和 Blob 技術,提供現代化的文件處理體驗。

/**
 * 單一密碼複製功能 / Single password copy functionality
 * 使用現代 Clipboard API 進行安全的剪貼簿操作
 */
copyPassword() {
    const passwordDisplay = document.getElementById('passwordDisplay');
    if (!passwordDisplay) {
        console.error('找不到密碼顯示元素');
        return;
    }
    
    const password = passwordDisplay.textContent;
    if (!password || passwordDisplay.classList.contains('empty')) {
        console.warn('沒有可複製的密碼');
        return;
    }
    
    const t = this.translations[this.currentLanguage];
    const copyBtn = document.getElementById('copyBtn');
    
    // 使用 Clipboard API 進行複製 / Use Clipboard API for copying
    navigator.clipboard.writeText(password).then(() => {
        console.log('密碼已複製到剪貼簿');
        
        // 顯示複製成功反饋 / Show copy success feedback
        if (copyBtn) {
            const originalText = copyBtn.textContent;
            copyBtn.textContent = t.copiedBtn;
            copyBtn.style.background = '#27ae60';
            
            // 1秒後恢復原狀 / Restore after 1 second
            setTimeout(() => {
                copyBtn.textContent = t.copyBtn;
                copyBtn.style.background = '';
            }, 1000);
        }
        
    }).catch(err => {
        console.error('複製失敗:', err);
        
        // 備用複製方案 / Fallback copy method
        this.fallbackCopyToClipboard(password);
    });
}

/**
 * 批次密碼複製功能 / Batch password copy functionality
 * 將所有生成的密碼複製為純文字格式
 */
copyAllPasswords() {
    if (!this.passwords || this.passwords.length === 0) {
        console.warn('沒有可複製的批次密碼');
        return;
    }
    
    const allPasswords = this.passwords.join('\n');
    const t = this.translations[this.currentLanguage];
    const copyAllBtn = document.getElementById('copyAllBtn');
    
    navigator.clipboard.writeText(allPasswords).then(() => {
        console.log(`已複製 ${this.passwords.length} 個密碼到剪貼簿`);
        
        // 顯示複製成功反饋 / Show copy success feedback
        if (copyAllBtn) {
            const originalText = copyAllBtn.textContent;
            copyAllBtn.textContent = t.copiedBtn;
            copyAllBtn.style.background = '#27ae60';
            
            setTimeout(() => {
                copyAllBtn.textContent = t.copyAll;
                copyAllBtn.style.background = '';
            }, 1000);
        }
        
    }).catch(err => {
        console.error('批次複製失敗:', err);
        this.fallbackCopyToClipboard(allPasswords);
    });
}

/**
 * 備用複製方案 / Fallback copy method
 * 當 Clipboard API 不可用時的傳統複製方法
 */
fallbackCopyToClipboard(text) {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.style.position = 'fixed';
    textArea.style.opacity = '0';
    
    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();
    
    try {
        const successful = document.execCommand('copy');
        if (successful) {
            console.log('備用複製方案成功');
        } else {
            console.error('備用複製方案也失敗了');
        }
    } catch (err) {
        console.error('備用複製方案執行失敗:', err);
    }
    
    document.body.removeChild(textArea);
}

/**
 * 多格式下載功能 / Multi-format download functionality
 * 支援 TXT 和 CSV 格式的批次密碼下載
 */
downloadPasswords(format) {
    if (!this.passwords || this.passwords.length === 0) {
        console.warn('沒有可下載的密碼');
        return;
    }
    
    let content = '';
    let filename = '';
    let mimeType = 'text/plain;charset=utf-8';
    const t = this.translations[this.currentLanguage];
    const timestamp = new Date().toISOString().slice(0, 10);
    
    if (format === 'txt') {
        // TXT 格式:純文字,每行一個密碼 / TXT format: plain text, one password per line
        content = this.passwords.join('\n');
        filename = `passwords_${timestamp}.txt`;
        
    } else if (format === 'csv') {
        // CSV 格式:結構化資料 / CSV format: structured data
        const csvRows = this.passwords.map((pwd, index) => {
            // 轉義密碼中的雙引號 / Escape double quotes in password
            const escapedPassword = pwd.replace(/"/g, '""');
            // 用雙引號包圍密碼以防止特殊字符問題 / Wrap password in quotes for special characters
            return `${index + 1},"${escapedPassword}"`;
        });
        
        content = t.csvHeader + '\n' + csvRows.join('\n');
        filename = `passwords_${timestamp}.csv`;
        mimeType = 'text/csv;charset=utf-8';
        
    } else {
        console.error('不支援的下載格式:', format);
        return;
    }
    
    // 使用 Blob API 創建檔案 / Use Blob API to create file
    try {
        const blob = new Blob([content], { type: mimeType });
        const url = URL.createObjectURL(blob);
        
        // 創建隱藏的下載連結 / Create hidden download link
        const downloadLink = document.createElement('a');
        downloadLink.href = url;
        downloadLink.download = filename;
        downloadLink.style.display = 'none';
        
        // 觸發下載 / Trigger download
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        
        // 清理 URL 物件 / Clean up URL object
        setTimeout(() => {
            URL.revokeObjectURL(url);
        }, 100);
        
        console.log(`${format.toUpperCase()} 格式下載完成: ${filename} (${this.passwords.length} 個密碼)`);
        
    } catch (error) {
        console.error('下載失敗:', error);
        alert(`下載失敗: ${error.message}`);
    }
}

🚀 批次顯示與工具初始化

批次密碼的顯示管理和工具的完整初始化流程。包含密碼列表渲染、按鈕狀態管理、DOM就緒檢測和實例化。 確保工具在各種載入情況下都能正確初始化。

/**
 * 批次密碼顯示管理 / Batch password display management
 * 動態渲染批次生成的密碼列表
 */
displayBatchPasswords() {
    const listElement = document.getElementById('batchPasswordList');
    if (!listElement) {
        console.error('找不到批次密碼列表元素');
        return;
    }
    
    // 清空現有內容 / Clear existing content
    listElement.innerHTML = '';
    
    if (!this.passwords || this.passwords.length === 0) {
        const t = this.translations[this.currentLanguage];
        listElement.textContent = t.noPasswordsGenerated;
        return;
    }
    
    // 渲染密碼列表 / Render password list
    this.passwords.forEach((password, index) => {
        const passwordItem = document.createElement('div');
        passwordItem.className = 'password-item';
        passwordItem.textContent = `${index + 1}. ${password}`;
        
        // 添加點擊複製功能 / Add click-to-copy functionality
        passwordItem.addEventListener('click', () => {
            navigator.clipboard.writeText(password).then(() => {
                console.log(`已複製密碼 #${index + 1}`);
                
                // 短暫高亮效果 / Brief highlight effect
                passwordItem.style.background = '#e8f5e8';
                setTimeout(() => {
                    passwordItem.style.background = '';
                }, 500);
            }).catch(err => {
                console.error('複製密碼失敗:', err);
            });
        });
        
        // 添加 hover 提示 / Add hover tooltip
        passwordItem.title = '點擊複製此密碼';
        passwordItem.style.cursor = 'pointer';
        
        listElement.appendChild(passwordItem);
    });
    
    console.log(`已顯示 ${this.passwords.length} 個批次密碼`);
}

/**
 * 批次功能按鈕顯示管理 / Batch function button display management
 * 控制批次模式下功能按鈕的顯示狀態
 */
showBatchButtons() {
    const buttons = [
        'copyAllBtn',
        'downloadTxtBtn', 
        'downloadCsvBtn'
    ];
    
    buttons.forEach(buttonId => {
        const button = document.getElementById(buttonId);
        if (button) {
            button.style.display = 'inline-block';
            
            // 添加淡入動畫效果 / Add fade-in animation effect
            button.style.opacity = '0';
            button.style.transition = 'opacity 0.3s ease';
            
            requestAnimationFrame(() => {
                button.style.opacity = '1';
            });
        }
    });
    
    console.log('批次功能按鈕已啟用');
}

/**
 * 語言相關輔助更新方法 / Language-related helper update methods
 * 更新批次模式和密碼強度的語言顯示
 */
updateBatchModeLanguage(t) {
    // 更新批次模式標題 / Update batch mode title
    const batchTitle = document.querySelector('#batchMode h2');
    if (batchTitle) batchTitle.textContent = t.batchTitle;
    
    // 更新批次數量標籤 / Update batch count label
    const batchCountLabel = document.querySelector('label[for="batchCount"]');
    if (batchCountLabel) batchCountLabel.textContent = t.batchCount;
    
    // 更新單位文字 / Update unit text
    const batchUnit = document.querySelector('.input-group span');
    if (batchUnit && batchUnit.textContent.includes('筆密碼') || batchUnit.textContent.includes('passwords')) {
        batchUnit.textContent = t.batchUnit;
    }
    
    // 更新批次列表標籤 / Update batch list label
    const batchLabels = document.querySelectorAll('#batchMode .control-group label');
    batchLabels.forEach(label => {
        if (label.textContent === '批次密碼列表' || label.textContent === 'Batch Password List') {
            label.textContent = t.batchList;
        }
    });
    
    // 更新批次列表內容(如果為空) / Update batch list content (if empty)
    const batchList = document.getElementById('batchPasswordList');
    if (batchList && this.passwords.length === 0) {
        batchList.textContent = t.noPasswordsGenerated;
    }
}

updatePasswordStrengthLanguage(t) {
    // 更新密碼強度文字 / Update password strength text
    const strengthText = document.getElementById('strengthText');
    if (strengthText && strengthText.textContent) {
        const strengthClass = strengthText.className.split(' ').find(c => c.startsWith('strength-'));
        if (strengthClass) {
            const strength = strengthClass.replace('strength-', '');
            const strengthMap = {
                'weak': t.weak,
                'medium': t.medium,
                'strong': t.strong
            };
            const score = strengthText.textContent.match(/\d+/);
            if (score && strengthMap[strength]) {
                strengthText.textContent = `${t.passwordStrength}: ${strengthMap[strength]} (${score[0]}%)`;
            }
        }
    }
}

/**
 * 程式碼卡片切換功能 / Code card toggle functionality
 * 為技術文檔頁面提供展開/收合功能
 */
function toggleCodeCard(header) {
    const content = header.nextElementSibling;
    const icon = header.querySelector('.toggle-icon');
    
    if (content.style.display === 'none' || content.style.display === '') {
        content.style.display = 'block';
        header.classList.add('expanded');
        icon.textContent = '▼';
    } else {
        content.style.display = 'none';
        header.classList.remove('expanded');
        icon.textContent = '▶';
    }
}
}

// 工具初始化 / Tool initialization
// 確保 DOM 完全載入後再初始化密碼產生器
document.addEventListener('DOMContentLoaded', () => {
    console.log('DOM 已載入,開始初始化密碼產生器');
    
    try {
        // 檢查必要的 DOM 元素是否存在 / Check if necessary DOM elements exist
        const requiredElements = [
            'passwordLength',
            'generateBtn',
            'passwordDisplay'
        ];
        
        const missingElements = requiredElements.filter(id => !document.getElementById(id));
        
        if (missingElements.length > 0) {
            console.warn('缺少必要元素:', missingElements);
            // 延遲重試初始化 / Retry initialization with delay
            setTimeout(() => {
                new PasswordGenerator();
            }, 500);
        } else {
            // 立即初始化 / Initialize immediately
            window.passwordGenerator = new PasswordGenerator();
            console.log('密碼產生器初始化完成');
        }
        
    } catch (error) {
        console.error('密碼產生器初始化失敗:', error);
        
        // 最後一次重試 / Final retry attempt
        setTimeout(() => {
            try {
                window.passwordGenerator = new PasswordGenerator();
                console.log('密碼產生器延遲初始化完成');
            } catch (retryError) {
                console.error('密碼產生器延遲初始化也失敗:', retryError);
            }
        }, 1000);
    }
});

總結

密碼產生器展示了現代 Web 安全工具的最佳實踐,結合了加密級隨機數生成、多因子強度評估、雙語系統整合和企業級批次處理功能。 使用 Web Crypto API 確保了密碼的安全性,而完整的 UI/UX 設計則提供了優秀的用戶體驗。 這個實作可以作為其他安全工具開發的參考範例。