Electron桌面应用&&实现一个简单MarkDown应用
Electron介绍
Electron集成了chromium(支持最新特性的浏览器)与Node.js(javascript运行时,可实现文件读写)Native API是(提供统一原生界面操作的能力)
工作流程:启动APP 启动主进程,创建窗口,加载指定界面,开启渲染进程,渲染进程需要进行通信(如新增歌曲打开文件夹选择MP3文件)需通过主进程调用原生API进行操作
主进程可以看做是package.json中的main属性所对应的文件,一个应用只有一个主进程,只有主进程可以进行GUI操作,windows中展示的界面通过渲染进程实现,一个应用有多个渲染进程。
官网中含有起步项目
electron实质是在node环境下使用electron包
生命周期
ready: app 初始化完成
dom-ready: 一个窗口中的文本加载完成
did-finsh-load: 导航完成时触发窗口
window-all-closed: 所有窗口都被关闭时触发
before-quit: 在关闭窗口之前触发
will-quit: 在窗口关闭并且应用退出时触发
quit: 当所有窗口被关闭时触发
closed: 当窗口关闭时触发,此时应删除窗口引用
自启动配置
可以将窗体默认不去显示,然后监听窗体的ready-to-show事件让窗体进行显示
渲染进程是html通过<script>
标签导入的js,在渲染进程引入const o = require('electron')
去创建窗口(须在创建主进程窗口时添加如下红框中的配置),ctrl+shift+i调出调试的面板
通过remote模块与主进程进行通信
自定义窗口样式可将frame设置为false隐藏,然后在html文件中通过css来设置,js的编写下载DOMContentLoaded的监听中,通过原生方法获取元素
window.onbeforeunload 是一个JavaScript 事件处理器,在用户关闭当前页面(标签页)之前触发。
模态窗口,子窗口没有关闭之前父窗口不允许使用
自定义菜单
主进程模块下的Menu模块
角色和类型,配置项的role字段和type字段,设置快捷键
动态创建菜单:
自定义右键菜单:1)用Menu创建一个自定义菜单内容2)在鼠标右击行为发生之后显示出来
主进程与渲染进程之间通信
ipcMain模块是在主进程通信需要用到的
渲染进程的消息是在浏览器中查看到的,同步APIsend加上Sync
主进程给渲染进程通信,需要现有一个menu,主进程获取当前窗口使用APIgetFocusedWindow()
渲染进程和渲染进程之间通信
一种方式是通过主进程,另一种方式是要通过localStorage
通过id获取到窗口
dialog模块、shell模块和iframe模块
消息通知
全局快捷键globalShortcut模块
剪切板操作(clipboard字剪切,nativeImage图片剪切模块)
react和electron的markdowm项目
首先初始化一个react项目,然后在package.json中添加mian字段,为main.js,在main.js中引入electron来创建应用
使用以下工具创建应用
bootstrap: UI组件库
styled-components:自定义样式(一个流行的 CSS-in-JS 库)
将react启动窗口放置到electron生成的APP窗口中
const urlLocation = isDev ? "http://localhost:3000" : 'myUrl'
mainWindow.loadURL(urlLocation)
利用工具创建命名启动时不启动浏览器直接启动elecrtron应用,并且等到本地localhost完全运行后在显示桌面应用不至于有太长的白屏时间
"dev": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron .\""
electron-is-dev
concurrently: 连接多个命令,中间使用空格分开
wait-on:等待某个结果执行之后再去执行后续的命令
cross-env : 跨平台的环境变量设置
软件图标库
https://fontawesome.com/icons
@fortawesome/fontawesome-svg-core: 核心文件需要安装
@fortawesome/react-fontawesome :react 风格
@fortawesome/free-solid-svg-icons :solid 类型字体库
react中判断弄tab页时判断是否要添加该类名需要用classNames的包
markdown开源的能够和react开发的编辑器react-simplemde-editor,可在github上查看它的使用
利用文件方法来进行真正的文件读取,重命名,删除,保存操作
封装文件读取,删除重命名方法在js中,通过electron-store进行存储
执行导入模块
const importFile = () =>{
remote.dialog.showOpenDialog({
defaultPath:__dirname,
buttonLabe:'请选择',
title:"选择md文件",
properties:['openFile','multiSelections'],
filters:[
{"name":"md文档",extensions:["md"]},
{"name":"其他类型",extensions:["js","json","html"]}
]
}).then((ret)=>{
const paths = ret.filePaths
if(paths.length){
// 01 判断当前路径们,是否存在于files当中,如果已经存在则无需在执行导入操作const validPaths
//02 将上述的路径信息组装成files格式,id title path
//03 将上述数据格式处理为files所需要的
// 04 更新数据重新渲染
// 完成数据持久化操作
//成功导入提示
if(packageData.length){
remote.dialog.showMessageBox({
type:'info',
title:'导入md文档',
message:'文件导入成功'
})
}
}else{
console.log('未选择文件导入!')
}
})
}
自定义钩子实现右键菜单
将所需要的数据通过data-自定义菜单来挂载到元素上例如<li data-id={file.id}></li>
因为自定义属性挂载在li上,如果点击li中的元素就获取不到自定义属性值,所以需要获取到它的父级元素上面带着data-自定义属性的方法
export const getParentNode = (node,parentClassName)=>{
let currentEle = node
while(currentEle !== null) {
if(currentEle.classList.contains(parentClassName)){
return currentEle
}
currentEle =currentEle.parentNode
}
}
传入右键菜单配置项和类名(只在这触发显示右键菜单的元素)来生成右键菜单
function useContextMenu(contextMenuTmp, areaClass) {
const currentEle = useRef(null)
useEffect(() => {
// 获取需要触发右键菜单的区域的元素
const areaEle = document.querySelector(areaClass)
const menu = Menu.buildFromTemplate(contextMenuTmp)
const contextMenuHandle = (ev) => {
if (areaEle.contains(ev.target)) {
currentEle.current = ev.target
menu.popup({ window: remote.getCurrentWindow })
}
}
window.addEventListener('contextmenu', contextMenuHandle)
return () => {
window.removeEventListener('contextmenu', contextMenuHandle)
}
})
return currentEle
}
自定义原生菜单
自定义原生菜单用到原生菜单主进程和渲染进程之间的通信
const template = [
{
label: '文件',
submenu: [
{
label: '新建',
accelerator: 'CmdOrCtrl+N',
click(menuItem, browserWindow, event) {
browserWindow.webContents.send('execute-create-file')
}
},
]
},
{
label: '编辑',
submenu: [
{
label: '撤销',
accelerator: 'CmdOrCtrl + Z',
role: 'undo'//已有的功能
},
{
type: 'separator'
},
]
},
{
label: '视图',
submenu: [
{
label: '刷新',
accelerator: 'Shift + CmdOrCtrl + R',
click(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.reload()
}
}
},
]
},
{
label: '帮助',
role: 'help',
submenu: [
{
label: '更多',
click() {
shell.openExternal("http://electronjs.org")
}
}
]
}
]
在渲染进程中通信定义自定义钩子
import { useEffect } from 'react'
const { ipcRenderer } = window.require('electron')
function useIpcRenderer(actionMap) {
useEffect(() => {
Object.keys(actionMap).forEach((action) => {
ipcRenderer.on(action, actionMap[action])
})
return () => {
Object.keys(actionMap).forEach((action) => {
ipcRenderer.removeListener(action, actionMap[action])
})
}
})
}
其使用
// 实现主进程与渲染进程的事件通信
useIpcRenderer({
'execute-create-file': createFile,
})
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)