Electron 入门

本文介绍了如何使用Electron构建应用,包括配置package.json和nodemon,创建index.html并处理跨域,主进程与渲染进程的通信,进程隔离策略以及菜单管理和窗口定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Electron入门

一、Electron 脚手架

1、添加 package.json

Electron + JS + 原生

nodemon 可以自动兼容文件变化,重启Electron客户端

{
  "name": "electron-app",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon --exec electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "electron": "^28.0.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}

nodemon.json

{
  "ignore": [
    "node_modules",
    "dist"
  ],
  "colours": true,
  "verbose": true,
  "watch": [
    "*.*"
  ],
  "ext": "html,js"
}

Electron + Vite + 任意框架

concurrently 执行同时执行多命令

{
  "name": "electron-vue",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "main": "main.cjs",
  "scripts": {
    "dev": "concurrently \"vite\" \"electron .\"",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "concurrently": "^8.2.2",
    "electron": "^28.0.0",
    "vue": "^3.3.8"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.5.0",
    "typescript": "^5.2.2",
    "vite": "^5.0.0",
    "vue-tsc": "^1.8.22"
  }
}

2、添加index.html

配置跨域

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'" />

3、添加main.js

const createWindow = () => {
	const mainWindow = new BrowserWindow({
		width: 1000,
		height: 800,
		x: 20,
		y: 20,
		alwaysOnTop: false,
		frame: true,
		transparent: false,
	});

	mainWindow.loadURL(path.resolve(__dirname, 'index.html'));
	mainWindow.webContents.openDevTools();
    
	return mainWindow;
}

app.whenReady().then(() => {
	createWindow();
})

另外推荐一个 React + TypeScript + Vite + Electron 的脚手架

https://github.com/maxstue/vite-reactts-electron-starter

二、Electron 进程通信

1、Electron 进程

Electron 主进程与渲染进程同时支持Node环境,但一般的,为了渲染进程安全,建议通过进程通信的方式在渲染进程中使用Node.

Electron 进程分为 主进程 main.js,渲染进程 renderer.js,预加载进程 preload.js

预加载进行用于预加载事件通信。

注册preload.js 预加载进程

const mainWindow = new BrowserWindow({
	webPreferences: {
		preload: path.resolve(__dirname, 'preload.js'),
		nodeIntegration: true,
	}
})

2、渲染进程向主进程发送消息

  1. 预渲染进程注册 IPC通道
contextBridge.exposeInMainWorld('api', {
	IPC_SET_TITLE: (preload) => ipcRenderer.send('CHANNEL_SET_TITLE', preload),
}
  1. 渲染进程向 IPC 通道发送消息
function createFormElement () {
	const input = document.createElement('input');
	input.name = 'title'
	const button = document.createElement('button');
	button.innerText = 'Submit'

	button.type = 'submit';

	const form = document.createElement('form');
	form.onsubmit = (event) => {
		event.preventDefault();

		const inputTitle = event.target.querySelector('input[name="title"]').value
		window.api.IPC_SET_TITLE(inputTitle)
	}

	form.appendChild(input);
	form.appendChild(button);

	document.body.appendChild(form);
}
  1. 在主进程监听 IPC 通道消息
ipcMain.on('CHANNEL_SET_TITLE', (event, preload) => {
	//获取用于控制网页的webContents对象
	const webContents = event.sender
	//获取窗口
	const win = BrowserWindow.fromWebContents(webContents)
	//设置窗口标题
	win.setTitle(preload)
})

3、主进程向渲染进程发送消息

一个Electron菜单向页面发送消息的例子

  1. 预渲染进程注册 IPC通道
IPC_INCREMENT: (callback) => ipcRenderer.on('CHANNEL_INCREMENT', callback)

这里注册的是一个监听通道事件,它返回了一个回调函数,每当有通道消息,都会触发callback回调函数。

callback 它的类型大概是这样的

(event, preload) => any
  1. 菜单向IPC 通道发送消息

注册菜单:

// const mainWindow = new BrowserWindow(...)
createMenu(mainWindow);

menu.js

const { Menu } = require('electron')

function createMenu(win) {
	const menu = Menu.buildFromTemplate([
		{
			label: '菜单',
			submenu: [
				{	//主进程向渲染进程发送消息
					click: () => win.webContents.send('CHANNEL_INCREMENT', 1),
					label: '增加',
				},
			],
		},
	]);
	Menu.setApplicationMenu(menu);
}

module.exports = { createMenu }
  1. 重写 IPC_INCREMENT 函数,使其能够被 IPC通道 调用。

renderer.js

window.api.IPC_INCREMENT((event, value) => {
	const h1 = document.querySelector('h1');
	h1.innerHTML = Number(h1.innerText) + value;

	event.sender.send('CHANNEL_FINISH', h1.innerHTML); // 这个可以直接用
    // window.api.IPC_FINISH(h1.innerHTML); 这个需要在preload里先注册
})
  1. main.js
ipcMain.on('CHANNEL_FINISH', (event, preload) => {
	console.log(preload) // IDE 打印 1 2 3 4
})

4、Invoke 双向通信

  1. preload.js 注册通道
IPC_MAIN_SHOW: async (preload) =>  {
		console.log('IPC_MAIN_SHOW', preload);
		return ipcRenderer.invoke('CHANNEL_MAIN_SHOW', preload) // Promise<T>
}
  1. main.js 向通道 返回数据
app.whenReady().then(() => {
	createWindow();
	ipcMain.handle('CHANNEL_MAIN_SHOW', () => {
		return 'is main handle'
	})
})
  1. renderer 拿到通道 返回的数据,并向通道传入新的请求参数
function createInvokeButton () {
	const btn = document.createElement('button');
	btn.innerText = 'Invoke';
	btn.onclick = async () => {
		const res = await api.IPC_MAIN_SHOW('renderer');
		document.body.insertAdjacentText('afterend', res);
	}
	document.body.appendChild(btn)
}

三、进程隔离

参考文档:https://doc.houdunren.com/%E7%B3%BB%E7%BB%9F%E8%AF%BE%E7%A8%8B/electron/4%20%E9%9A%94%E7%A6%BB%E8%BF%9B%E7%A8%8B.html#%E4%B8%8A%E4%B8%8B%E6%96%87%E9%9A%94%E7%A6%BB

进程隔离有三个选项

contextIsolation 上下文隔离

nodeIntegration 集成Node

sandbox 沙盒环境

const mainWindow = new BrowserWindow({
	webPreferences: {
		preload: path.resolve(__dirname, 'preload.js'),
		contextIsolation: false,
		nodeIntegration: true,
		sandbox: false,
	},
})

隔离的配置有几种情况:

  • 默认 contextIsolation 为 true,nodeIntegration为 false,sandbox为true(安全,啥API用不了)

    • 此时main.js 为完全node环境,renderer 和 preload 为浏览器环境
  • nodeIntegration 为 true(推荐)

    • nodeIntegration 为 true,sandbox 自动设置 true,可以在preload中使用各种Node 高级模块,比如fs 等
  • nodeIntegration 为 true,sandbox为 false(不安全,啥API用不了)

    • 只能在preload 中用一些很低级的模块
  • contextIsolation为 false(不安全)

    • 不支持 contextBridge.exposeInMainWorld 等 API,在开启Node集成,关闭沙盒后,可以直接在render.js 中 使用完整的 NodeJS API,不安全

四、窗口定义

窗口实例常用的方法

方法说明
win.loadFile()加载文件
win.loadURL()加载链接
win.webContents.openDevTools()打开开发者工具
win.setContentBounds()控制窗口尺寸与位置
win.center()将窗口移动到屏幕中心

常用的窗口属性

属性说明
title标题,也可以修改html模板的title标签,模板的title标签优先级高
iconwindow系统窗口图标
frame是否显示边框
transparent窗口是否透明
xx坐标
yy坐标
width宽度
height高度
movable是否可以移动窗口
minHeight最小高度,不能缩放小于此高度
minWidth最大高度,不能缩放小于此高度
resizable是否允许缩放窗口
alwaysOnTop窗口是否置顶
autoHideMenuBar是否自动隐藏窗口菜单栏。 一旦设置,菜单栏将只在用户单击 Alt 键时显示
fullscreen是否全屏幕

五、菜单管理

在electron中可以方便的对应用菜单进行定义。

清除菜单

下面先来学习不显示默认菜单,在主进程main.js中定义以下代码。

const { BrowserWindow, app, Menu } = require('electron')
Menu.setApplicationMenu(null)

我们需要用到 Menu (opens new window)模块、MenuItem (opens new window)菜单项与 accelerator (opens new window)快捷键知识。

const { Menu, BrowserWindow } = require('electron')

const isMac = process.platform === 'darwin'

function createMenu(window) {
	const menu = Menu.buildFromTemplate([
		{
			label: '菜单',
			submenu: [
				{
					label: '打开新窗口',
					click: () => new BrowserWindow({ width: 800, height: 600 }).loadURL('https://baidu.com'),
					accelerator: 'CommandOrControl+n',
				},
				{ //主进程向渲染进程发送消息
					label: '增加',
					click: () => window.webContents.send('CHANNEL_INCREMENT', 1),
				},
			],
		},
		{
			type: 'separator',
		},
		isMac
			? { label: '关闭', role: 'close' }
			: { role: 'quit' },
	]);
	Menu.setApplicationMenu(menu);
}

module.exports = {
	createMenu,
}

右键菜单

electron 可以定义快捷右键菜单,需要预加载脚本与主进程结合使用

main.js 主进程定义ipc事件,当preload.js 触发事件时显示右键菜单

ipcMain.on('show-context-menu', (event) => {
  const popupMenuTemplate = [
    { label: '退出', click: () => app.quit() },
  ]

  const menu = Menu.buildFromTemplate(
    popupMenuTemplate,
  )
  menu.popup(
    BrowserWindow.fromWebContents(event.sender),
  )
})

preload.js 预加载脚本定义,用于触发右键事件,然后通过IPC调用主进程显示右键菜单

window.addEventListener('contextmenu', (e) => {
  e.preventDefault()
  ipcRenderer.send('show-context-menu')
})
### Electron框架入门教程 #### 什么是ElectronElectron 是一个用于构建跨平台桌面应用程序的开源框架,它允许开发者利用 JavaScript、HTML 和 CSS 创建原生桌面应用。通过嵌入 Chromium 和 Node.js,Electron 可以让开发者仅维护一套基于 Web 的代码库,从而实现跨 Windows、macOS 和 Linux 平台的应用程序开发[^3]。 --- #### 安装与环境准备 要开始使用 Electron,首先需要安装 Node.js 和 npm(Node Package Manager)。可以通过以下命令验证是否已正确安装: ```bash node -v && npm -v ``` 如果尚未安装,请访问官方页面下载最新版本:[Node.js官网](https://nodejs.org/)。 接着,在项目目录下初始化一个新的 Node.js 应用程序,并安装 Electron: ```bash npm init -y npm install electron --save-dev ``` 上述操作会创建 `package.json` 文件并将 Electron 添加到项目的依赖项中[^1]。 --- #### 基本结构 一个典型的 Electron 应用通常包含以下几个文件: - **main.js**: 这是主进程脚本,负责管理窗口和操作系统之间的交互。 - **index.html**: 渲染界面的内容。 - **renderer.js (可选)**: 渲染进程中使用的逻辑脚本。 下面是一个简单的示例配置: ##### main.js 这是主进程的核心部分,定义了如何启动和关闭应用程序以及创建浏览器窗口。 ```javascript const { app, BrowserWindow } = require('electron'); function createWindow() { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation: false, }, }); win.loadFile('index.html'); } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); ``` ##### index.html 这是一个基本的 HTML 页面,作为应用的主要视图。 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Electron App</title> </head> <body> <h1>Hello from Electron!</h1> <p>This is a basic example of an Electron application.</p> </body> </html> ``` --- #### 启动应用 完成以上设置后,可以在 `package.json` 中添加一条启动脚本来简化流程: ```json { "name": "my-electron-app", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron ." } } ``` 随后运行以下命令来启动您的第一个 Electron 应用: ```bash npm start ``` 这将会打开一个带有自定义内容的新窗口[^2]。 --- #### 使用 electron-vite 加速开发 对于希望提升性能和体验的开发者来说,可以尝试使用 electron-vite 工具链。该工具旨在提供更快、更精简的开发体验,主要分为五个模块化组件进行优化[^2]。以下是其快速搭建方法: ```bash npm create vite@latest my-electron-project --template vanilla cd my-electron-project npm install electron @electron/vite-plugin-main-process-renderer ``` 更多细节请参考官方文档或相关资源链接。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值