Vue3和Electron实现桌⾯端应⽤详解
⽬录
Vue CLI 搭建Vue项⽬
Vue项⽬改造为markdown编辑器
Vue CLI Plugin Electron Builder
优化功能
启动全屏显⽰
修改菜单栏
编辑器打开markdonw⽂件的内容
markdonw的内容存⼊⽂件
打包
题外话:VS Code就是⽤Electron开发出来的桌⾯应⽤,我现在除了移动端的开发外,其他的都是使⽤VS Code来开发了,各种插件开发起来真的很⽅便。
接下来我就带⼤家来⼀步步来实现这个功能。
Vue CLI 搭建Vue项⽬
选择的⽬录下执⾏vue create electron-vue3-mark-down
选择⾃定义的模板(可以选择默认的Vue 3 模板)
选择Vue3 和 TypeScript, 其他的选项基于⾃⾝项⽬决定是否选择
执⾏npm run serve看看效果
Vue项⽬改造为markdown编辑器
执⾏npm i @kangc/v-md-editor@next -S安装v-md-editor
添加TypeScript类型定义⽂件
由于v-md-editor这个库没有TypeScript类型定义⽂件,我就直接在shims-vue.d.ts这个⽂件的后⾯添加的,当然也可以新建⼀个⽂件添加申明(tsconfig.json能到这个⽂件就OK)。declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
<!-- 添加的内容 -->
declare module "@kangc/v-md-editor/lib/theme/vuepress.js";
declare module "@kangc/v-md-editor/lib/plugins/copy-code/index";
declare module "@kangc/v-md-editor/lib/plugins/line-number/index";
declare module "@kangc/v-md-editor";
declare module "prismjs";
改造App.vue
<template>
<div>
<v-md-editor v-model="content" height="100vh"></v-md-editor>
</div>
</template>
<script lang="ts">
// 编辑器
import VMdEditor from "@kangc/v-md-editor";
import "@kangc/v-md-editor/lib/style/base-editor.css";
import vuepress from "@kangc/v-md-editor/lib/theme/vuepress.js";
import "@kangc/v-md-editor/lib/theme/style/vuepress.css";
// ⾼亮显⽰
import Prism from "prismjs";
import "prismjs/components/prism-json";
import "prismjs/components/prism-dart";
import "prismjs/components/prism-c";
import "prismjs/components/prism-swift";
import "prismjs/components/prism-kotlin";
import "prismjs/components/prism-java";
// 快捷复制代码
import createCopyCodePlugin from "@kangc/v-md-editor/lib/plugins/copy-code/index";
import "@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css";
// ⾏号
import createLineNumbertPlugin from "@kangc/v-md-editor/lib/plugins/line-number/index";
VMdEditor.use(vuepress, {
Prism,
})
.use(createCopyCodePlugin())
.use(createLineNumbertPlugin());
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "App",
components: { VMdEditor },
setup() {
const content = ref("");
return { content };
},
});
</script>
<style>
/* 去掉⼀些按钮 */
.v-md-icon-save,
.
v-md-icon-fullscreen {
display: none;
}
</style>
这个⽂件也很简单,整个页⾯就是⼀个编辑器<v-md-editor v-model="content" height="100vh"></v-md-editor>,这个markdown编辑器有⾼亮显⽰,代码显⽰⾏号,复制代码按钮等插件,当然更⽅便的是可以添加其他的插件丰富这个markdown编辑器的功能.
效果如下
Vue CLI Plugin Electron Builder
我尝试过⽤Vite 2.0去搭建Electron项⽬,但是没有到类似的Vite和Electron结合好使的⼯具,所以放弃了Vite 2.0的诱惑。如果有⼩伙伴有推荐可以分享下。
使⽤vue add electron-builder安装,我选择的是13.0.0的Electron的最新版本。
我⼀般是选择最⾼的版本,其实这个版本有坑,我后⾯再想想要不要介绍下这个坑,哈哈。
我们看到新加了很多的依赖库,还添加了⼀个background.ts⽂件。简单介绍下,这个⽂件执⾏在主线程,其他的页⾯都是在渲染线程。渲染线程有很多限制的,有些功能只能在主线程执⾏,这⾥就不具体展开了。
执⾏npm run electron:serve看效果
⾄此,就可以看到桌⾯应⽤的效果了,并且边修改Vue的代码,桌⾯应⽤也能实时看到修改后的效果。
优化功能
启动全屏显⽰
引⼊screen
import { screen } from "electron";
创建窗⼝的时候设置为screen⼤⼩
<!-- background.ts -->
async function createWindow() {
const { width, height } = PrimaryDisplay().workAreaSize;
const win = new BrowserWindow({
width,
height,
// 省略...
});
// 省略...
}
这样应⽤启动的时候就是全屏显⽰了。
修改菜单栏
定义菜单栏
<!-- background.ts -->
const template: Array<MenuItemConstructorOptions> = [
{
label: "MarkDown",
submenu: [
{
label: "关于",
accelerator: "CmdOrCtrl+W",
role: "about",
},
{
label: "退出程序",
accelerator: "CmdOrCtrl+Q",
role: "quit",
},
],
},
{
label: "⽂件",
{
label: "打开⽂件",
accelerator: "CmdOrCtrl+O",
click: (
item: MenuItem,
focusedWindow: BrowserWindow | undefined,
图片编辑器app
_event: KeyboardEvent
) => {
// TODO: 打开⽂件
},
},
{
label: "存储",
accelerator: "CmdOrCtrl+S",
click: (
item: MenuItem,
focusedWindow: BrowserWindow | undefined,
_event: KeyboardEvent
) => {
// TODO: 存储内容
},
},
],
},
{
label: "编辑",
submenu: [
{
label: "撤销",
accelerator: "CmdOrCtrl+Z",
role: "undo",
},
{
label: "重做",
accelerator: "Shift+CmdOrCtrl+Z",
role: "redo",
},
{
type: "separator",
},
{
label: "剪切",
accelerator: "CmdOrCtrl+X",
role: "cut",
},
{
label: "复制",
accelerator: "CmdOrCtrl+C",
role: "copy",
},
{
label: "粘贴",
accelerator: "CmdOrCtrl+V",
role: "paste",
},
],
},
{
label: "窗⼝",
role: "window",
submenu: [
{
label: "最⼩化",
accelerator: "CmdOrCtrl+M",
role: "minimize",
},
{
label: "最⼤化",
accelerator: "CmdOrCtrl+M",
click: (
item: MenuItem,
focusedWindow: BrowserWindow | undefined,
_event: KeyboardEvent
) => {
if (focusedWindow) {
focusedWindow.maximize();
}
},
},
{
type: "separator",
},
{
label: "切换全屏",
accelerator: (function () {
if (process.platform === "darwin") {
return "Ctrl+Command+F";
} else {
return "F11";
}
})(),
click: (
item: MenuItem,
focusedWindow: BrowserWindow | undefined,
/
/ eslint-disable-next-line @typescript-eslint/no-unused-vars
_event: KeyboardEvent
) => {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());          }
},
},
],
},
{
label: "帮助",
role: "help",
submenu: [
{
label: "学习更多",
click: function () {
shell.openExternal("electron.atom.io");
},
},
],
},
];
具体如何定义参阅。
打开⽂件和存储⽬前还没实现,后⾯实现。
import { Menu } from "electron";
<("ready", async () => {
// 省略...
// 创建菜单
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
});
在ready钩⼦函数中进⾏设置Menu。
效果
编辑器打开markdonw⽂件的内容
主线程选择⽂件,将⽂件路径传给渲染线程
<!-- background.ts -->
dialog
.showOpenDialog({
properties: ["openFile"],
filters: [{ name: "Custom File Type", extensions: ["md"] }],
})
.then((res) => {
if (res && res["filePaths"].length > 0) {
const filePath = res["filePaths"][0];
// 将⽂件传给渲染线程
if (focusedWindow) {
focusedWindow.webContents.send("open-file-path", filePath);
}
}
})
.catch((err) => {
console.log(err);
});
showOpenDialog是打开⽂件的,我们这⾥指定了只打开md⽂件;
获得⽂件路径后,通过focusedWindow.webContents.send("open-file-path", filePath);这个⽅法将⽂件路径传给渲染线程。渲染线程取到⽂件路径,读取⽂件内容,赋值给markdown编辑器
<!-- App.vue -->
import { ipcRenderer } from "electron";
import { readFileSync } from "fs";
export default defineComponent({
// 省略...
setup() {
const content = ref("");
onMounted(() => {
// 1.
<("open-file-path", (e, filePath: string) => {
if (filePath && filePath.length > 0) {
// 2.
content.value = readFileSync(filePath).toString();
}
});
});
return { content };
},
});
vue添加node⽀持
<!-- fig.js -->
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
},
},
};
效果