简单介绍
目前网上有好多关于electron相关的文章,但是本人在开发的时候发现,网上大部分文章可以说是千篇一律,没有真正的痛点解析啥的很无语 ,好多的问题都需要自己去找、去试,这无异于加大了开发成本与学习成本,所以本篇博客会从electron 的api 到 electron +vue 组合式开发到 打包 及开发过程中遇见的问题分门别类的进行说明, 当然在最后的文末我会将我写的 electron + vue全家桶的git开源项目附上,需要的话就去git 吧
electron基础 (基础补习)
什么是electron
Electron 是一个框架,可以让您使用 JavaScript, HTML 和 CSS 创建桌面应用程序。 然后这些应用程序可以打包在macOS、Windows和Linux上直接运行,或者通过Mac App Store或微软商店分发。 通常,您使用每个操作系统特定的本地应用程序框架为操作系统 (OS)创建一个桌面应用程序。 Electron 可以在使用您已经知道的技术后写入您的应用程序。
electron 的两个进程(重点)
electron 主要分为两个进程 分别是主进程和渲染进程
- 主进程 通过创建浏览器窗口实例来创建 个网页。 每一个
浏览窗口
实例在其渲染过程中运行网页. 当一个BrowserWindow
实例被摧毁时,对应的渲染过程也被终止。
-主进程 管理所有 个网页及其对应的渲染过程。
渲染进程 只能管理 个相应的网页。 在一个渲染过程中崩溃不会影响其他渲染过程。
渲染进程 通过IPC 与主进程通信 在网页上执行GUI操作。 由于安全考虑和可能的资源泄漏,直接从渲染器过程中调用与本地GUI有关的API受到限制。
流程之间的通信可以通过进程间通信模块进行:ipcMain
和ipcRenderer
接下来分别说一下渲染进程和主进程
/* 个人认为electron的难点的主要就是 主进程和渲染进程之间的通信, 其次就是关于electron的api了,接下来我们一起来揭开这个小东西的神秘面纱吧!! */ • 1 • 2 • 3
创建主脚本文件
主脚本指定了您将运行主进程的 Electron 应用程序的入口点(通常情况下是 main.js 文件)【后续代码结构中会有示例说明】。 通常,在主进程中运行的脚本控制应用程序的生命周期,并显示图形用户界面及其元素。 执行本机操作系统交互,并在网页中创建渲染程序。 Electron 应用程序只能有一个主流程。
主脚本可以如下所示:
1. const { app, BrowserWindow } = require('electron') 2. 3. function createWindow () { 4. const win = new BrowserWindow({ 5. width: 800, 6. height: 600, 7. webPreferences: { 8. nodeIntegration: true 9. } 10. }) 11. 12. win.loadFile('index.html') 13. win.webContents.openDevTools() 14. } 15. 16. app.whenReady().then(createWindow) 17. app.on('window-all-closed', () => { 18. if (process.platform !== 'darwin') { 19. app.quit() 20. } 21. }) 22. 23. app.on('activate', () => { 24. if (BrowserWindow.getAllWindows().length === 0) { 25. createWindow() 26. } 27. }) 28.
这段代码说的是啥嘞 😮😮
- 第1行:为了管理您应用程序的生命周期事件,以及创建和控制浏览器窗口,您从
electron
软件包导入了app
和BrowserWindow
模块 。 - 第 3 行:在此之后,您定义一个函数,该函数创建一个 新的浏览窗口 启用了节点集成,将
index.html
文件加载到此窗口中(第 12 行,稍后我们将讨论该文件),并打开开发人员工具(第 13 行)。 - 第 16 行:你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
- 第 18 行:您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 因为操作系统 窗口管理行为 ,此监听器在 macOS 上是一个禁门。
- 第 24 行:您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后,或重新启动已在运行的应用程序。
渲染进程是啥呢 ?? 😒😒
所谓的渲染进程说白了就是你写的html
页面 这不用过多的浪费口舌了 , 后面的实例中会用到,只要有前端基础的 童鞋都会掌握滴
electron API
如果 要在两个 进程中访问Electron Api ,首先需要引入他包含的模块
const electron = require('electron')
若要创建一个窗口,需要调用 ·浏览窗口· 类,并且只能在主进程中使用:
const { BrowserWindow } = require('electron') const win = new BrowserWindow()
若要从渲染器调用主流程,则需要使用 IPC 模块:
// 在主进程中 const { ipcMain } = require('electron') ipcMain.handle('exper-action', (evidence, ...args) => // ... 代表渲染器操作 })
// 在渲染过程中 const { ipcRenderer } = require('electron') ipcRender.invotrake('exper-action', ...args)
如何在渲染进程中通讯主进程
我们发现在上面的代码中 通讯的操控主要在主进程 ,通过主进程来控制渲染进程,然后渲染进程会将把响应的事件返回到主进程然后在对我们的页面进行操作 ,接下来我们按照这种思路写一个关于自定义窗口放大缩小关闭的代码吧!! 感受下 😜😜😜
效果如图
先看下我的项目目录结构吧
代码书写
// 渲染进程代码如下 <template> <el-row> <el-col :span="24"> <div class="grid-content bg-purple-dark"> <!-- <el-button class="btnOut" @click="handleOutWeb" type="text">操作说明</el-button> --> <div class="rightEdit"> <i title="最小化" class="el-icon-minus" @click="min"></i> <i :title="title" :class="changeClass" @click="max"></i> <i title="关闭" class="el-icon-close" @click="close"></i> </div> </div> </el-col> </el-row> </template> <script> let ipcRenderer = require('electron').ipcRenderer; export default { name: "Navbar", data() { return { changeClass: "el-icon-full-screen", // el-icon-copy-document 最小化窗口 title: "全屏" }; }, methods: { min(){ //发送最小化命令 ipcRenderer.send('window-min'); }, max(){ //发送最大化命令 ipcRenderer.send('window-max'); if (this.changeClass === 'el-icon-full-screen') { this.changeClass = 'el-icon-copy-document' this.title ="最小化" }else{ this.changeClass = 'el-icon-full-screen' this.title ="全屏" } }, close(){ //发送关闭命令 ipcRenderer.send('window-close'); } } }; </script> <style lang="scss" scoped> .... </style>
关于css的代码我就不写了 , 自己去git 上拿吧 https://gitee.com/ruochengflag/mint-video/tree/host/
在host 分支上哦!
在上面的代码中我们可以看到当我点击min
、max
、close
三个按钮时 会通过 ipcRenderer.send
将指令发送到主进程中 ,在主进程中进行判断 , 接下来我们看下主进程中是如何写的嘞
// 在main 文件夹下的 index.js 中 //引入 let ipcMain = require('electron').ipcMain; // 通过命令进行判断 //接收最小化命令 ipcMain.on('window-min', function() { mainWindow.minimize(); }) //接收最大化命令 ipcMain.on('window-max', function() { if (mainWindow.isMaximized()) { mainWindow.restore(); } else { mainWindow.maximize(); } }) //接收关闭命令 ipcMain.on('window-close', function() { mainWindow.close(); })
OK , 到目前为止核心代码就 ok 了 , 接下来就是细节处理了
第一点 去除系统自带的导航
将主进程中添加 frame : false;
mainWindow = new BrowserWindow({ height: 700, useContentSize: true, maximizable: false, // 默认不能最大化 width: 1000, // resizable: false, frame: false, // 去除自带导航 show: false //消除启动时白屏 , 如果想做启动页效果的话会用到 })
第二点 可拖拽区域
当我们写完自定义导航时会发现窗口无法拖拽 , 啥原因呢?
应用程序需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖拽的
在可拖拽区域内部使用 -webkit-app-region: no-drag 则可以将其中部分区域排除
拖动行为可能与选择文本冲突。 例如, 当您拖动标题栏时, 您可能会意外地选择标题栏上的文本。 为防止此操作, 您需要在可区域中禁用文本选择
我们可以添加如下代码来解决
.titlebar { -webkit-app-region: drag; -webkit-user-select: none; }
好了 到目前为止第一种通讯方式已经解决了 , 我们会发现这种通讯方式有些麻烦, 难道所有的通讯都这样解决吗 ?
很心累啊 !!!不要着急 我们还有 第二种 解决办法
第二种通讯方式
在这里只说核心代码 ,其他的问提如 隐藏系统导航 ,拖拽的实现解决办法通第一种哦!!!
第二种方法只需要在渲染进程进行修改就可以了 , 我们无需在去主进程修改代码
<template> <el-row> <el-col :span="24"> <div class="grid-content bg-purple-dark"> <!-- <el-button class="btnOut" @click="handleOutWeb" type="text">操作说明</el-button> --> <div class="rightEdit"> <i title="最小化" class="el-icon-minus" @click="minimizeWin"></i> <i :title="title" :class="changeClass" @click="maximizeWin"></i> <i title="关闭" class="el-icon-close" @click="closeWin"></i> </div> </div> </el-col> </el-row> </template> <script> import { remote } from "electron"; export default { name: "Navbar", data() { return { changeClass: "el-icon-full-screen", title: "全屏" }; }, methods: { minimizeWin() { remote.getCurrentWindow().minimize(); }, maximizeWin() { // 如果已处于最大化则恢复 if (remote.getCurrentWindow().isMaximized()) { remote.getCurrentWindow().restore(); this.changeClass = "el-icon-full-screen"; this.title = "全屏"; } else { remote.getCurrentWindow().maximize(); this.changeClass = "el-icon-copy-document"; this.title = "向下还原"; } }, closeWin() { remote.getCurrentWindow().close(); } } }; </script> <style lang="scss" scoped> ... </style>
在这里我们主要通过引入 rem
ote
来进行通讯就可以了, 无需其他操作哦 ! 代码在master
分支自己自行下载。
在使用 Element-ui 的时候Table无法正常显示
在使用Electron-vue搭配使用Element-ui的时候, 在使用Table表格的时候, 会出现页面一片空白, 使用F12进行审查元素的时候,表格的高度为0,而下面的tbody下面也是只是渲染了几个tr空标签,而自己也是找了好久的问题
解决问题
打开
/webpack.renderer.config.js
文件搜索whiteListedModules
//let whiteListedModules = ['vue'] //将这行修改为下面的的内容 let whiteListedModules = ['vue', 'element-ui']
再次运行就好了
electron 如何打开外部链接 【点击连接时在默认浏览器打开链接】
关于打开默认浏览器 , 通常情况下我们 会用原声js 的方法 window.locationg.herf
或者 open
等方法来打开,但是在electron 中这种方法是不起作用滴是不是很抓狂 , 其实也很好解决
我们需要
import { remote , shell } from "electron"; // 点击事件 handleOutWeb(){ shell.openExternal( "https://www.baidu.com" ); }
这样就可以了
好了到目前为止 关于
electron
的部分内容已经完事了 ,实力有限有好多地方没有在这里写 比如:在electron 中无法打开接口返回的视频链接 , 会返回403 , 这个问题 可以在 我的另一个开源项目中找到
https://gitee.com/ruochengflag/mint.git
, 在这里,master
分支是模板分支 可以直接进行二次开发 ,mint-video
分支是视频分支 , 有时间就写一下, 目前还在更新中!如果你也在做相关的项目欢迎交流下哈,
electron +vue全家桶 + element-ui 项目搭建
新建项目
- 初始化项目
electron-vue
是vue-cli
和electron
结合的项目,比单独使用 vue 构建起的 electron 项目要方便很多.打开cmd,新建一个项目,我使用的是 electron-vue,输入以下命令:
vue init simulatedgreg/electron-vue my-project
my-project
就是我们自己取的项目名。
安装elementui
npm install element-ui -s
然后在
main.js
文件中全局引入,打开src/renderer/main.js
:
import Element from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(Element)
ok 搭建完成 ,
tips:
补充一点:
如果你运行项目时 ,没有打开页面也没有报错, 而是显示项目目录, 这种情况下,应该是你的eslint 语法校验的问题,你可以吧eslint 语法校验的规则注释了 ,就可以了 , 但是如果安装的时候不同意elslint 的话好像也会报错 ,不知道为啥, 自己尝试吧。
创作不易给个赞哇!!!!!