目录
项目背景
框架版本
框架的个人理解
项目搭建
electron搭建
blockly(大坑)
开发
blockly
吐槽
electron
loadFile和loadURL
BrowserWindow.getAllWindows()
项目背景
笔者之前主要是做后端,前端只了解一点点,用的也是vue2,但是工作需求要去做前端。虽然需求说使用的是vue3,奈何不会ts,vue3当vue2用。¯\_(ツ)_/¯
electron官方文档:简介 | Electron (electronjs.org)
element-plus官方文档:Button 按钮 | Element Plus (element-plus.org)
blockly官方文档:Blockly 简介 | Blockly 中文文档 (tortorse.com)
框架版本
vue:
electron:
blockly:8.0.5
element-plus:
electron-vite:
框架的个人理解
electron是一个使用前端三件套搭建桌面应用的框架,本身内容并不复杂,更多的是用来将你写出来的网页与操作系统建立联系,这么说不太严谨,官方一点的话语叫做“深化与操作系统和 Node.js 的集成”,至于页面的具体内容,你使用vue、react等框架都不会有任何影响,因此,在要求不高的情况下,你甚至可以只参照官网文档提供的教程去完成项目的electron框架部分。
blockly是Google提供的一个开源的库,有点类似低代码平台,但是是纯JavaScript开发的,100%客户端,不会与服务器有任何接触,可以用它去做可视化编程软件。
至于element-plus,也是比较常用的一个ui库了,不再过多介绍。
项目搭建
electron搭建
笔者用的是electron-vite搭建项目,官方文档在这:快速开始 | electron-vite (cn-evite.netlify.app)
因为是个前端小白,按照官方文档的步骤走的时候出了个糗。跟着官方文档安装electron-vite,然后去创建项目,官方文档里只贴了几种方式的创建语句:
yarn create @quick-start/electron
笔者小白想知道@quick-start/electron里的quick-start是不是项目名,于是将@quick-start换成了test,执行!
yarn create v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...warning "create-test@1.0.0" has no binaries
[1G[##] 2/2'C:\Users\XXX\AppData\Local\Yarn\bin\create-test' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
error Command failed.
Exit code: 1
Command: C:\Users\XXX\AppData\Local\Yarn\bin\create-test
Arguments:
Directory: C:\Users\XXX\Desktop\test
Output:info Visit https://yarnpkg.com/en/docs/cli/create for documentation about this command.
???
这一下直接给笔者整蒙了,研究了一下报错信息(然后发现看不懂)。又换回去执行,这次没有任何问题,接着就是和官方文档贴出来的一样,一路往下进行配置,最后运行,畅通无阻。笔者好奇心被勾起来了,正常来讲项目名一定是可以更改的,并且执行创建语句后还有一次提示输入项目名,为什么会有两个项目名?为什么不能改项目名?带着这些疑问笔者询问了做前端的朋友。。。然后就出糗了。。。
@quick-start/electron并不是什么项目名,而是一个模块包!它提供了一个 Electron 项目的基础模板。豁然开朗,难怪执行后还要输入项目名,难怪改了“项目名”后执行报错。如果不想使用这个模板的创建语句应该是下面这样:
npm create my-electron-app-name
这里的my-electron-app-name才是项目名
blockly(大坑)
根据笔者的经验,blockly库绝对是Google某个或某些员工的kpi产物。整个官方文档观感体验极差,所谓的中文文档纯机翻,而且整篇文档示例极少,大部分都只有概念介绍
而且不止是机翻的问题,有些地方介绍含糊不清
这里的参考是官方提供的api吗?是模块还是什么?完全不知道用法,而且你需要科学上网才能点进具体内容然后才知道“哦哦哦,原来是这么用的”
还有,整个官方文档的示例代码都是基于纯JavaScript开发,没有其它任何使用框架的示例,这一点非常令人头疼,这年头谁还纯js开发
如果是个人开发,强烈建议不要使用blockly!
开发
开发内容主要是vue+blockly,electron基本只是个项目运行的壳子,只用到了和Windows系统的交互
blockly
blockly有个功能代码生成器,将工作区中的块转换成你想要的代码,按照官方文档的步骤,这只是个三四行代码的小问题,但是折磨了笔者一天半,中间咨询了前端朋友和ChatGPT,最后还是自己去翻源码才试出来了正确写法
官方文档写法:
1. 引入相关语言的生成器,注意要先引入blockly_compressed.js。不同的语言引入不同的js文件,具体参考官方文档
<script src="blockly_compressed.js"></script>
<script src="python_compressed.js"></script>
2. 使用代码生成器
var code = Blockly.Python.workspaceToCode(workspace);
很简单对吧,但是笔者用的是vue,肯定不是这么写的,于是笔者前往百度,得到以下写法
vue写法:
import Blockly from "blockly";
import 'blockly/python';var code = Blockly.Python.workspaceToCode(workspace);
还是很简单对吧!好!保存!执行!
(꒪⌓꒪)
笔者随后咨询了ChatGPT,也是这种写法,询问前端朋友,被告知肯定是方法调用错了,报错信息是workspaceToCode未被定义,这个方法肯定不是这种方式调用,但是笔者手上还有一个能正确启动运行的项目,也是这种写法。笔者试过换版本等方法,但就是两个项目一个报错,一个没问题。随后开始研究源码。
成功写法:
import { pythonGenerator } from "blockly/python";var code= pythonGenerator.workspaceToCode(workspace);
两个写法读者都可以试一下,看一下哪个能正确使用,具体导致报错的原因笔者也不清楚
吐槽
这垃圾库真有点毛病,笔者上周使用下面的写法成功运行之后就没动了,这周一回来一跑又报错,改成上面的写法后又成功了。。。建议读者两个都试一下
electron
由于electron框架是运行在Node和浏览器两个环境中的,所以划分出了主进程和渲染进程两个概念,主进程的运行环境是Node,渲染进程是浏览器。笔者项目的需求是通过electron的Node环境进行文件的读写操作,两个进程各有各的操作,这就涉及到electron的进程通信
进程间通信 | Electron (electronjs.org)
没有什么很复杂的东西,按照示例就可以实现。但是如果是读写文件需要注意一点,调用的方法是Node的fs.readFile和fs.writeFile,这两个方法都是异步操作的!如果需要获取数据返回值,可以使用promise封装方法。主要就是搞清楚主进程写哪些东西,渲染进程写哪些东西,然后通过官方提供的api调用进程间的通信就可以了。
读文件操作示例:
main.js(主进程):
async function load() {const readF = () => {return new Promise((res, rej) => {fs.readFile('./code.json', 'utf-8', (err, data) => {if (!err) {res(data)} else {rej(err)throw err}})})}const JSONData = await readF()return JSONData
}//创建窗口前加入主进程的监听
app.whenReady().then(() => {ipcMain.handle('load', () => load())createWindow()
})
preload.js(预加载):
contextBridge.exposeInMainWorld('file', {//向渲染进程暴露通知主进程读取文件的方法load: () => ipcRenderer.invoke('load')})
renderer.vue(渲染进程):
<template>
<button @click="load()">读取</button>
<p v-text="code"></p>
</template><script setup>
const code = ref();
async function load() {//调用预加载暴露的方法const data = await window.file.load()code.value = JSON.parse(data)
}
</script>
路径问题
另外,关于在main和preload文件夹下文件中写到的相对路径,都是基于out目录下对应的main和preload下的对应文件,这点需要注意
loadFile和loadURL
loadURL可以加载外部资源,也就是包括网站等非你项目包里的资源
loadFile只能加载包里有的文件
两个方法读取本地资源时都无法识别vue文件,会将内容全部作为文本显示在页面上,只能识别html文件并渲染
BrowserWindow.getAllWindows()
这个方法返回的窗口数组需要注意的是,新创建的窗口是从数组头部插入的,也即是如果你需要实现这种场景:打开一个新窗口并关闭原来的窗口,应该使用
// 在此之前是new BrowserWindow操作
const wins = BrowserWindow.getAllWindows()
wins[1].close()
而不是wins[length - 2].close()