Contents

Electron 無法使用 prompt

在 Electron 應用程式中,呼叫 window.prompt()window.alert()window.confirm() 等原生瀏覽器對話框時,會發現這些函式完全無效,沒有任何對話框彈出。這是 Electron 的架構設計造成的,需要用其他方式替代。

為什麼 Electron 不支援原生 Dialog?

Electron 採用 Main Process / Renderer Process 的雙進程架構:

  • Main Process(主進程):Node.js 環境,負責管理視窗、系統資源等,對應 main.js
  • Renderer Process(渲染進程):Chromium 環境,負責顯示 UI,對應網頁內容

window.prompt() 等原生對話框在標準瀏覽器中是同步阻塞的,但 Electron 基於安全性和效能考量,在 Renderer Process 中停用了這些同步對話框。呼叫後會被靜默忽略,prompt() 永遠回傳 null

替代方案一:Electron 內建 dialog 模組(Main Process)

Electron 提供 dialog 模組,可在 Main Process 中顯示系統原生對話框:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// main.js(Main Process)
const { app, BrowserWindow, dialog, ipcMain } = require('electron');

// 監聽來自 Renderer 的請求
ipcMain.handle('show-input-dialog', async (event, message) => {
    const result = await dialog.showMessageBox({
        type: 'question',
        buttons: ['確定', '取消'],
        title: '輸入',
        message: message,
    });
    return result.response;  // 0 = 確定, 1 = 取消
});
1
2
3
4
5
6
7
// renderer.js(Renderer Process)
const { ipcRenderer } = require('electron');

async function myPrompt(message) {
    const response = await ipcRenderer.invoke('show-input-dialog', message);
    return response === 0;  // 回傳 true 代表點了確定
}

注意:dialog 模組只能在 Main Process 使用,必須透過 IPC(Inter-Process Communication)從 Renderer 呼叫。

替代方案二:自訂 HTML Modal 對話框

直接在頁面中用 HTML + CSS 實作對話框,是最靈活的方式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- 對話框 HTML -->
<div id="custom-prompt" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:9999;">
  <div style="background:white; margin:100px auto; padding:20px; width:300px; border-radius:8px;">
    <p id="prompt-message"></p>
    <input type="text" id="prompt-input" style="width:100%; padding:8px;">
    <br><br>
    <button onclick="promptConfirm()">確定</button>
    <button onclick="promptCancel()">取消</button>
  </div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
function showPrompt(message) {
    return new Promise((resolve) => {
        document.getElementById('prompt-message').textContent = message;
        document.getElementById('prompt-input').value = '';
        document.getElementById('custom-prompt').style.display = 'block';

        window.promptConfirm = () => {
            const value = document.getElementById('prompt-input').value;
            document.getElementById('custom-prompt').style.display = 'none';
            resolve(value);
        };

        window.promptCancel = () => {
            document.getElementById('custom-prompt').style.display = 'none';
            resolve(null);
        };
    });
}

// 使用方式
const name = await showPrompt('請輸入您的姓名:');

替代方案三:使用第三方套件

electron-prompt

專為 Electron 設計的 prompt 替代套件:

1
npm install electron-prompt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const prompt = require('electron-prompt');

prompt({
    title: '輸入',
    label: '請輸入您的姓名:',
    value: '預設值',
    inputAttrs: {
        type: 'text'
    },
    type: 'input'
}).then((result) => {
    if (result === null) {
        console.log('使用者取消');
    } else {
        console.log('輸入值:', result);
    }
});

SweetAlert2

功能豐富的 dialog 替代套件,支援各種樣式:

1
npm install sweetalert2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const Swal = require('sweetalert2');

const { value } = await Swal.fire({
    title: '請輸入您的姓名',
    input: 'text',
    inputPlaceholder: '輸入姓名...',
    showCancelButton: true,
});

console.log('輸入值:', value);

方案比較

方案 適用情境 優點 缺點
Electron dialog(IPC) 需要系統原生外觀 與 OS 整合,使用者熟悉 需要 IPC,程式碼較複雜
自訂 HTML Modal 需要高度自訂樣式 完全控制外觀 需要自行實作
electron-prompt 快速替換 prompt() 簡單易用 功能較簡單
SweetAlert2 需要豐富的 UI 外觀漂亮、功能多 需要引入額外套件

參考資料