Electron桌面应用开发基础
2023/6/10 1:22:30
本文主要是介绍Electron桌面应用开发基础,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Electron桌面应用开发
Electron技术架构
地址:快速入门 | Electron
- Chromium 支持最新特性的浏览器
- Node.js Javascript运行时,可实现文件读写
- Native APIS 提供统一的原生界面能力
环境搭建
-
Node 安装 (我的版本14.15.0)
-
项目初始化
npm init -y // 安装Electron npm i --save-dev electron // 创建main.js 并在package.json中设置为入口 "main":"main.js" // 创建index.html 用来书写页面内容
-
初始化代码
package.json
{ "name": "myElectron", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "start": "nodemon --watch main.js --exec npm run build", "build": "electron ." }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "electron": "^24.4.0" }, "dependencies": { "@electron/remote": "^2.0.9" } }
main.js
const { app, BrowserWindow } = require( 'electron' ) // app 哪个控制应用程序的事件生命周期 // BrowserWindow 创建和管理应用程序Windows const createWindow = () => { let mainWin = new BrowserWindow( { width: 800, height: 600, show: false, backgroundColor: 'aqua', } ) mainWin.loadFile( 'index.html' ) mainWin.on( 'ready-to-show', () => { mainWin.show() } ) mainWin.on( 'close', () => { mainWin = null } ) } app.on( 'ready', () => { createWindow() } )
生命周期事件 // 执行顺序如下
-
ready: app初始化完成
-
dom-ready: 一个窗口中的文本加载完成
-
did-finsh-load: 导航完成时触发
-
closed:当窗口关闭时触发,此时应删除窗口引用
-
window-all-closed: 所有窗口关闭时触发
-
before-quit: 在关闭窗口之前触发
-
will-quit: 在窗口关闭并且应用退出时触发
-
quit: 当所有窗口被关闭时触发
-
mainWin.webContents.on( 'did-finish-load', () => { console.log( '333-did-finish-load' ); } ) // 窗口中文本加载完成 mainWin.webContents.on( 'dom-ready', () => { console.log( '222dom-ready' ); } ) // 主窗口关闭 mainWin.on( 'closed', () => { console.log( '88888-事件发生' ); } ) app.on( 'window-all-closed', () => { console.log( '444-window-all-closed' ); if ( process.platform !== 'darwin' ) app.quit() } ) app.on( 'ready', () => { console.log( '111- app初始化完成' ); createWindow() } ) app.on( 'before-quit', () => { console.log( '555-before-quit' ); } ) app.on( 'will-quit', () => { console.log( '666-will-quit' ); } ) app.on( 'quit', () => { console.log( '777-quit' ); } )
窗口设置
const mainWin = new BrowserWindow( { x: 100, //x y 窗口开始位置 y: 100, show: false, width: 800, height: 600, minHeight: 400, // min max 最小最大宽高 minWidth: 50, maxHeight: 1000, maxWidth: 1200, resizable: false, // 窗口是否可调整 minimizable: true, maximizable: true, title: '桌面应用', frame: false, // autoHideMenuBar: true, webPreferences: { nodeIntegration: true, // 运行渲染进程使用node enableRemoteModule: true, contextIsolation: false } } ) require( '@electron/remote/main' ).initialize() require( "@electron/remote/main" ).enable( mainWin.webContents )
窗口标题及环境
-
标题配置
- 优先读取index.html中的title
- index.html中不设置得情况下 可以读取 new BrowserWindow 中配置的title
-
图标修改
icon -
frame 是否显示默认导航菜单 + 标题
-
transparent 设置透明
-
autoHideMenuBar 是否隐藏 导航菜单
-
点击打开新窗口
备注: 在main中运行时是主进程 在index.html中运行时是渲染进程
app BrowserWindow 都属于主进程得模块
出于安全考虑 渲染进程中没有办法使用require 可在main中配置
渲染进程不允许直接使用主进程模块 通过remote进行调用
electron 12 之后就已经废除了 remote
// 替换为:
const { BrowserWindow } = require('@electron/remote')
// 在主进程中:
require('@electron/remote/main').initialize()
自定义窗口实现
- 渲染进程中获取 主进程窗口实例
let mainWin = remote.getCurrentWindow() - 获取各个按钮
var btnGroup = document.getElementsByClassName( 'btnGroup' )[0].getElementsByTagName( 'button' ) - 是否最大判断
mainWin.isMaximized() - 最大化
mainWin.maximize() // 最大化还原 mainWin.restore()
- 最小化
mainWin.minimize()
// <div class="btnGroup"> // <button>最小</button> // <button>最大</button> // <button>关闭</button> // </div> // 获取按钮组 var btnGroup = document.getElementsByClassName( 'btnGroup' )[0].getElementsByTagName( 'button' ) btnGroup[0].addEventListener( 'click', () => { if ( !mainWin.isMinimized() ) { mainWin.minimize() } } ) btnGroup[1].addEventListener( 'click', () => { console.log( '最大化', mainWin.isMaximized() ); if ( !mainWin.isMaximized() ) { // 判断窗口是否最大化 mainWin.maximize() // 最大化 } else { mainWin.restore() } } ) btnGroup[2].addEventListener( 'click', () => { mainWin.close() } )
阻止窗口关闭
window.onbeforeunload = function() {
return false
}
动态创建菜单
- 准备模板
let menuArr = [{label:'打开',type:'normal',role:'copy'}]
- 利用模板生成菜单
let menu = Menu.buildFromTemplate( menuArr )
- 添加到应用
Menu.setApplicationMenu( menu )
let temp = [ { label: 'send', click () { BrowserWindow.getFocusedWindow().webContents.send( 'msg2', '主进程发来消息' ) } } ] let tem = Menu.buildFromTemplate( temp ) Menu.setApplicationMenu( tem ) // <button id="selfMenu">自定义菜单</button> // <input type="text" value="" id="inputText"> // <button id="addMenu">加入新增菜单</button> 1. 找到 Menu MenuItem 2. new Menu() 可以将 new MenuItem() 创建的菜单进行添加到菜单栏中 let remote = require( '@electron/remote' ) let Menu = remote.Menu let MenuItem = remote.MenuItem window.addEventListener( 'DOMContentLoaded', () => { // 获取按钮-- 自定义菜单 let selfBtn = document.getElementById( 'selfMenu' ) let inputVal = document.getElementById( 'inputText' ) let addMenu = document.getElementById( 'addMenu' ) let selfMenuItem = new Menu() selfBtn.addEventListener( 'click', () => { let menuFile = new MenuItem( { label: '文件', type: 'normal' } ) let menuEdit = new MenuItem( { label: '编辑', type: 'normal' } ) let menuSelf = new MenuItem( { label: '自定义菜单', submenu: selfMenuItem } ) let menu = new Menu() menu.append( menuFile ) menu.append( menuEdit ) menu.append( menuSelf ) Menu.setApplicationMenu( menu ) } ) addMenu.addEventListener( 'click', () => { let content = inputVal.value.trim() if ( content ) { selfMenuItem.append( new MenuItem( { label: content, type: 'normal' } ) ) content = '' } } ) })
右击弹出菜单
-
创建菜单
-
监听contextmenu 事件 并阻止默认行为
-
menu.popup({window:remote.getCurrentWindow()})
// 右键菜单 let rightMenu = [ { label: 'Run Code', type: 'normal' }, { label: '刷新', role: 'refresh' }, { type: 'separator' }, { label: '其他功能', click () { console.log( '其他功能已执行' ); } } ] let menuRight = Menu.buildFromTemplate( rightMenu ) window.addEventListener( 'contextmenu', ( e ) => { e.preventDefault() menuRight.popup( { window: remote.getCurrentWindow } ) } )
主进程与渲染进程通信
- ipcRender(on send) ipcMain( on ) 两个进程之间通信
- ipcMain 内部 e.sender.send('xx',xxx) - ipcMain 内部接收 e.returnValue
-
BrowserWindow.getFocusedWindow().webContents.send('mtp',来自于主进程的消息) // 依赖按钮之类的事件触发‘
-
mainWin.contents.openDevtools() // 打开控制台
// main.js let { app, BrowserWindow, ipcMain } = require( 'electron' ) ipcMain.on( 'msg1', ( e, ev ) => { console.log( e, ev ); e.sender.send( 'msg2', 666 ) // BrowserWindow.getFocusedWindow().webContents.send( 'msg2', 666 ) } ) // index.js let remote = require( '@electron/remote' ) let { ipcRenderer } = require( 'electron' ) window.addEventListener( 'DOMContentLoaded', () => { console.log( 666 ); ipcRenderer.send( 'msg1', '渲染进程发来贺电' ) ipcRenderer.on( 'msg2', ( e, ev ) => { console.log( e, ev ); } ) } )
localtorage通信
- 获取主窗口id
- BrowserWindow 实例属性 id
- 子窗口设置ID
- BrowserWindow.fromId(mainWin.id)
-
通信的时候存储 信息到localStorage中
-
新窗口打开时取值并使用
// main.js ipcMain.on( 'msg', ( e, data ) => { if ( data ) { // 开启第二个窗口 let sub2 = new BrowserWindow( { parent: BrowserWindow.fromId( mainId ), width: 300, height: 150, webPreferences: { nodeIntegration: true, enableRemoteModule: true, contextIsolation: false } } ) sub2.loadFile( 'sub.html' ) sub2.on( 'close', () => { sub2 = null } ) } } ) // 主进程接收窗口二的信息 ipcMain.on( 'toMain', ( e, data ) => { // 将数据转发给index进程 let mainOpen = BrowserWindow.fromId( mainId ) mainOpen.webContents.send( 'win2', data ) } ) // index.js let remote = require( '@electron/remote' ) let { ipcRenderer } = require( 'electron' ) window.addEventListener( 'DOMContentLoaded', () => { // 获取打开窗口按钮 let btnOpen = document.getElementById( 'openTwo' ) btnOpen.addEventListener( 'click', () => { localStorage.setItem( 'name', '张三' ) ipcRenderer.send( 'msg', true ) } ) ipcRenderer.on( 'win2', ( e, data ) => { console.log( 'index进程已经接收到', data ); } ) } )
渲染进程之间通信
- 主进程 A 渲染 B渲染
- A给B发生数据 ipcRender.send
- B接收 ipcRender.on
- B给A发数据 先发送给 主进程 主进程再发送给 A
- 注意: 主进程发送时不能直接使用BrowsserWindow.getFocusedWindow().webContents.send('mtp',来自于主进程的消息)
因为当前焦点窗口不一定时主进程窗口
dialog模块
- dialog模块: 主进程模块 在渲染进程中使用remote.diaog 调用对应触发得窗口api
- 配置:
remote.dialog.showOpenDialog( {
defaultPath: __dirname,
buttonLabel: '请选择',
title: '高傲的狼',
properties: ['openFile', 'multiSelections'],
filters: [
{ name: '代码文件', extensions: ['js', 'html', 'json'] },
{ name: '图片文件', extensions: ['ico', 'jpeg', 'png'] },
{ name: '媒体文件', extensions: ['mp3', 'mp4', 'avi'] },
]
} ).then( res => {
console.log( res );
} )
shell 打开url或者路劲
- shell.openExternal(url) 默认浏览器打开
- shell.showItemInFolder() 在桌面引用中打开
消息提示
- option = {
title:'高傲的狼',
body:'你好哇,小家伙',
icon:'./xxx.ico'
}
- window.Notification(
option.title,option
)
快捷键
- 注册
globalShortcut('ctrl + q') // 返回布尔值 true/false
- 判断是否注册过
globalShortcut.isRegistered('ctrl + q')
- 注销快捷键
- 时机 -- 在生命周期 will-quit中进行注销 - globalShortcut.unregister('ctrl + q')
剪切板模块
- clipboard 模块
- writeText - readText
- 图片复制 粘贴
- let img = nativeImage.createFromPath( './女孩.jpg' )
2. clipboard.writeImage( img )
- let img = nativeImage.createFromPath( './女孩.jpg' )
// 将剪贴版中图片写到DOM中 3. let oimg = clipboard.readImage() 4. let imgDom = new Image() 5. imgDom.src = oimg.toDataURL() 6. document.body.appendChild( imgDom )
这篇关于Electron桌面应用开发基础的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享