基于Electron27+React18
快速搭建跨平台应用|主进程与渲染进程通信
创建react18项目
这里使用vite构建工具创建react项目模板,由于官方提供的构建工具速度慢,构建后体积大,而vite构建速度快,运行体积小。
yarn create vite electron-vite4-react18
# 选择创建react模板
cd electron-vite4-react18
yarn install
yarn dev
运行yarn dev
命令,项目就启动起来了。
接下来安装一系列electron依赖包。
// 安装electron
yarn add -D electron
// 安装electron-builder 用于构建打包可安装exe程序
yarn add -D electron-builder
// 安装electron-devtools-installer 用于开发调试electron项目
yarn add -D electron-devtools-installer
还需要安装一个重要的vite和electron整合插件。
yarn add -D vite-plugin-electron
创建主进程/预加载文件
const { app, BrowserWindow } = require('electron')
const MultiWindow = require('./src/windows')
const createWindow = () => {
let win = new MultiWindow()
win.createWin({ isMainWin: true })
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
在vite.config.js
中配置主进程入口。
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import electron from 'vite-plugin-electron'
import { resolve } from 'path'
import { parseEnv } from './src/utils/env'
// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
const viteEnv = loadEnv(mode, process.cwd())
const env = parseEnv(viteEnv)
return {
plugins: [
react(),
electron({
entry: 'electron-main.js',
})
],
esbuild: {
// 打包去除 console.log 和 debugger
drop: env.VITE_DROP_CONSOLE && command === 'build' ? ["console", "debugger"] : []
},
/* 开发服务器配置 */
server: {
// 端口
port: env.VITE_PORT,
// 代理配置
proxy: {
// ...
}
},
resolve: {
// 设置别名
alias: {
'@': resolve(__dirname, 'src'),
'@assets': resolve(__dirname, 'src/assets'),
'@components': resolve(__dirname, 'src/components'),
'@views': resolve(__dirname, 'src/views')
}
}
}
})
配置package.json
文件。
{
"name": "electron-vite4-react18",
"private": true,
"version": "0.0.0",
"description": "基于Electron27+React18桌面端实践",
"author": "Andy <282310962@qq.com>",
"copyright": "MIT License(MIT) ©2023 Hs",
"main": "electron-main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"electron:serve": "vite --host",
"electron:build": "vite build && electron-builder"
},
"dependencies": {
"@arco-design/web-react": "^2.54.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.17.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.0.3",
"electron": "^27.0.1",
"electron-builder": "^24.6.4",
"electron-devtools-installer": "^3.2.0",
"eslint": "^8.45.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"vite": "^4.4.5",
"vite-plugin-electron": "^0.14.1"
}
}
运行 yarn electron:serve
一个桌面端项目就运行起来了。
关于一些electron-builder.json打包配置,大家可以去看看之前的分享文章。
electron自定义无边框拖拽窗口
设置frame: false
即可创建一个无边框窗口。
拖拽区设置-webkit-app-region: drag 来实现区块拖拽。设置 -webkit-app-region: no-drag 取消拖拽响应。
自定义操作按钮(最大化/最小化/关闭)
/**
* Electron自定义拖拽操作按钮
* @author Andy Q:282310962
*/
import { useState, useContext } from 'react'
import { Modal } from '@arco-design/web-react'
import { setWin } from '@/windows/action'
function WinBtn(props) {
const {
color = '#fff',
minimizable = true,
maximizable = true,
closable = true,
zIndex = 2023,
children
} = props
const [hasMaximized, setHasMaximized] = useState(false)
window.electronAPI.invoke('win__isMaximized').then(res => {
setHasMaximized(res)
})
window.electronAPI.receive('win__hasMaximized', (e, res) => {
setHasMaximized(res)
})
// 最小化
const handleWinMin = () => {
window.electronAPI.send("win__minimize")
}
// 最大化/还原
const handleWinMax2Min = () => {
window.electronAPI.invoke("win__max2min").then(res => {
console.log(res)
setHasMaximized(res)
})
}
// 关闭
const handleWinClose = () => {
if(window.config.isMainWin) {
Modal.confirm({
title: '提示',
content: <div style={{ textAlign: 'center' }}>是否最小化至托盘,不退出程序?</div>,
okButtonProps: {status: 'warning'},
style: {width: 360},
cancelText: '最小化至托盘',
okText: '残忍退出',
onOk: () => {
setWin('close')
},
onCancel: () => {
setWin('hide', window.config.id)
}
})
}else {
setWin('close', window.config.id)
}
}
return (
<>
<div className="vui__macbtn flexbox flex-alignc" style={{zIndex: zIndex}}>
<div className="vui__macbtn-groups flexbox flex-alignc" style={{color: color}}>
{ JSON.parse(minimizable) && <a className="mbtn min" title="最小化" onClick={handleWinMin}><svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#995700" d="M8.048,4.001c0.163,0.012 0.318,0.054 0.459,0.137c0.325,0.191 0.518,0.559 0.49,0.934c-0.007,0.097 -0.028,0.192 -0.062,0.283c-0.04,0.105 -0.098,0.204 -0.171,0.29c-0.083,0.098 -0.185,0.181 -0.299,0.24c-0.131,0.069 -0.271,0.103 -0.417,0.114c-2.031,0.049 -4.065,0.049 -6.096,0c-0.163,-0.012 -0.318,-0.054 -0.459,-0.137c-0.325,-0.191 -0.518,-0.559 -0.49,-0.934c0.007,-0.097 0.028,-0.192 0.062,-0.283c0.04,-0.105 0.098,-0.204 0.171,-0.29c0.083,-0.098 0.185,-0.181 0.299,-0.24c0.131,-0.069 0.271,-0.103 0.417,-0.114c2.031,-0.049 4.065,-0.049 6.096,0Z"></path></svg></a> }
{ JSON.parse(maximizable) &&
<a className="mbtn max" title={hasMaximized ? '向下还原' : '最大化'} onClick={handleWinMax2Min}>
{
hasMaximized ?
<svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M5,10c0,0 0,-2.744 0,-4.167c0,-0.221 -0.088,-0.433 -0.244,-0.589c-0.156,-0.156 -0.368,-0.244 -0.589,-0.244c-1.423,0 -4.167,0 -4.167,0l5,5Z"></path><path fill="#006400" d="M5,0c0,0 0,2.744 0,4.167c0,0.221 0.088,0.433 0.244,0.589c0.156,0.156 0.368,0.244 0.589,0.244c1.423,0 4.167,0 4.167,0l-5,-5Z"></path></svg>
:
<svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M2,3c0,0 0,2.744 0,4.167c0,0.221 0.088,0.433 0.244,0.589c0.156,0.156 0.368,0.244 0.589,0.244c1.423,0 4.167,0 4.167,0l-5,-5Z"></path><path fill="#006400" d="M8,7c0,0 0,-2.744 0,-4.167c0,-0.221 -0.088,-0.433 -0.244,-0.589c-0.156,-0.156 -0.368,-0.244 -0.589,-0.244c-1.423,0 -4.167,0 -4.167,0l5,5Z"></path></svg>
}
</a>
}
{ JSON.parse(closable) && <a className="mbtn close" title="关闭" onClick={handleWinClose}><svg x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path fill="#4d0000" d="M5,3.552c0.438,-0.432 0.878,-0.861 1.322,-1.287c0.049,-0.044 0.101,-0.085 0.158,-0.119c0.149,-0.091 0.316,-0.137 0.49,-0.146c0.04,0 0.04,0 0.08,0.001c0.16,0.011 0.314,0.054 0.453,0.135c0.08,0.046 0.154,0.104 0.218,0.171c0.252,0.262 0.342,0.65 0.232,0.996c-0.045,0.141 -0.121,0.265 -0.218,0.375c-0.426,0.444 -0.855,0.884 -1.287,1.322c0.432,0.438 0.861,0.878 1.287,1.322c0.097,0.11 0.173,0.234 0.218,0.375c0.04,0.126 0.055,0.26 0.043,0.392c-0.011,0.119 -0.043,0.236 -0.094,0.344c-0.158,0.327 -0.49,0.548 -0.852,0.566c-0.106,0.005 -0.213,-0.007 -0.315,-0.035c-0.156,-0.043 -0.293,-0.123 -0.413,-0.229c-0.444,-0.426 -0.884,-0.855 -1.322,-1.287c-0.438,0.432 -0.878,0.861 -1.322,1.287c-0.11,0.097 -0.234,0.173 -0.375,0.218c-0.126,0.04 -0.26,0.055 -0.392,0.043c-0.119,-0.011 -0.236,-0.043 -0.344,-0.094c-0.327,-0.158 -0.548,-0.49 -0.566,-0.852c-0.005,-0.106 0.007,-0.213 0.035,-0.315c0.043,-0.156 0.123,-0.293 0.229,-0.413c0.426,-0.444 0.855,-0.884 1.287,-1.322c-0.432,-0.438 -0.861,-0.878 -1.287,-1.322c-0.106,-0.12 -0.186,-0.257 -0.229,-0.413c-0.025,-0.089 -0.037,-0.182 -0.036,-0.275c0.004,-0.363 0.211,-0.704 0.532,-0.874c0.13,-0.069 0.272,-0.105 0.418,-0.115c0.04,-0.001 0.04,-0.001 0.08,-0.001c0.174,0.009 0.341,0.055 0.49,0.146c0.057,0.034 0.109,0.075 0.158,0.119c0.444,0.426 0.884,0.855 1.322,1.287Z"></path></svg></a> }
<i className="mr-10"></i>
{ children }
</div>
<div className="vui__mactitle">{window.config.title || '首页'}</div>
</div>
</>
)
}
export default WinBtn
OK,基于electron27+react18创建跨端项目实践就先分享到这里。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。