Electron.js实现仅显示自身全屏并冻结其他应用(可切换)
Electron 实现考试模式:锁定系统仅允许访问当前应用
我正在用 Electron.js 开发桌面应用,想要实现类似在线考试的效果:用户只能操作这个 Electron 应用,无法打开或切换到其他窗口/应用,而且这个锁定功能可以通过应用内的按钮开启和关闭。我从 AI 助手那里拿到了一段代码,但运行不起来,作为 Electron 新手,不知道该怎么解决。
原代码文件
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> <title>Hello World!</title> </head> <body> <h1>Block Other Applications</h1> <button id="blockButton">Block Other Apps</button> <script> const { ipcRenderer } = require('electron'); document.getElementById('blockButton').onclick = () => { alert('Blocking!') ipcRenderer.send('block-apps'); }; </script> </body> </html>
main.js
const path = require('node:path') app.whenReady().then(createMainWindow); ipcMain.on('block-apps', (event) => { createOverlayWindow(); }); ipcMain.on('restore-apps', (event) => { if (overlayWindow) { overlayWindow.close(); overlayWindow = null; } }); app.on('window-all-closed', () => { app.quit(); }); //Code to create an overlay let mainWindow; let overlayWindow; function createMainWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false, }, }); mainWindow.loadFile('index.html'); } function createOverlayWindow() { overlayWindow = new BrowserWindow({ width: 1920, // Set based on your screen resolution height: 1200, // Set based on your screen resolution frame: false, transparent: true, alwaysOnTop: true, resizable: false, movable: false, fullscreen: true, webPreferences: { nodeIntegration: true, contextIsolation: false, }, }); overlayWindow.loadFile('overlay.html'); }
overlay.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Overlay</title> <style> body { background-color: rgba(0, 0, 0, 0.8); color: white; display: flex; align-items: center; justify-content: center; height: 100vh; font-size: 2em; } </style> </head> <body> <div> Other applications are blocked. <br><br> <button id="restoreButton">Restore Access</button> </div> <script> const { ipcRenderer } = require('electron'); document.getElementById('restoreButton').onclick = () => { ipcRenderer.send('restore-apps'); }; </script> </body> </html>
问题分析与修复方案
原代码无法运行的核心问题是缺少Electron核心模块引入,同时存在逻辑顺序错误和安全隐患。以下是修复后的完整代码:
1. 修复后的 main.js
const { app, BrowserWindow, ipcMain, screen } = require('electron'); const path = require('node:path'); let mainWindow; let overlayWindow; // 创建主窗口 function createMainWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { // 启用预加载脚本,替代不安全的nodeIntegration preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false }, alwaysOnTop: false }); mainWindow.loadFile('index.html'); } // 创建全屏覆盖层窗口 function createOverlayWindow() { const primaryDisplay = screen.getPrimaryDisplay(); const { width, height } = primaryDisplay.workAreaSize; overlayWindow = new BrowserWindow({ width: width, height: height, frame: false, transparent: true, alwaysOnTop: true, resizable: false, movable: false, fullscreen: true, skipTaskbar: true, // 从任务栏隐藏 webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false } }); // 阻止用户通过快捷键关闭或切换窗口 overlayWindow.setMenu(null); overlayWindow.on('close', (e) => { if (overlayWindow) e.preventDefault(); // 除非主动触发恢复,否则禁止关闭 }); overlayWindow.loadFile('overlay.html'); } // IPC 事件监听 ipcMain.on('block-apps', () => { createOverlayWindow(); // 将主窗口置于最上层 mainWindow.setAlwaysOnTop(true); }); ipcMain.on('restore-apps', () => { if (overlayWindow) { overlayWindow.destroy(); overlayWindow = null; mainWindow.setAlwaysOnTop(false); } }); // Electron 生命周期事件 app.whenReady().then(createMainWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createMainWindow(); });
2. 新增预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron'); // 向渲染进程暴露安全的IPC接口 contextBridge.exposeInMainWorld('electronAPI', { blockApps: () => ipcRenderer.send('block-apps'), restoreApps: () => ipcRenderer.send('restore-apps') });
3. 修改后的 index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> <title>考试模式控制</title> </head> <body> <h1>考试模式控制</h1> <button id="blockButton">启用考试模式</button> <script> document.getElementById('blockButton').onclick = () => { window.electronAPI.blockApps(); }; </script> </body> </html>
4. 修改后的 overlay.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>考试模式已启用</title> <style> body { background-color: rgba(0, 0, 0, 0.8); color: white; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; font-size: 2em; } button { padding: 12px 24px; font-size: 0.8em; cursor: pointer; background-color: #4CAF50; color: white; border: none; border-radius: 4px; } </style> </head> <body> <div> 考试模式已启用,无法访问其他应用 <br><br> <button id="restoreButton">退出考试模式</button> </div> <script> document.getElementById('restoreButton').onclick = () => { window.electronAPI.restoreApps(); }; </script> </body> </html>
关键修复点说明
- 模块引入:补充了Electron核心模块
app、BrowserWindow、ipcMain、screen的引入,这是原代码无法运行的首要原因。 - 逻辑顺序:将变量声明和函数定义放在事件监听之前,避免未定义报错。
- 安全优化:启用
contextIsolation并使用预加载脚本,替代不安全的nodeIntegration: true,符合Electron最新安全规范。 - 屏幕适配:自动获取主显示器尺寸,替代硬编码的分辨率。
- 窗口控制:覆盖层窗口添加
skipTaskbar: true,并阻止默认关闭行为,增强锁定效果。 - 主窗口层级:启用考试模式时将主窗口置于最上层,确保用户能操作核心应用。
内容的提问来源于stack exchange,提问作者Sarang
相关产品推荐
相关产品推荐

