• 售前

  • 售后

热门帖子
入门百科

Vue3和Electron实现桌面端应用详解

[复制链接]
芊芊551 显示全部楼层 发表于 2021-8-14 14:41:11 |阅读模式 打印 上一主题 下一主题
目录


  • Vue CLI 搭建Vue项目
  • Vue项目改造为markdown编辑器

    • Vue CLI Plugin Electron Builder

  • 优化功能

    • 启动全屏表现
    • 修改菜单栏
    • 编辑器打开markdonw文件的内容
    • markdonw的内容存入文件
    • 打包

为了方便记载一些个人漫笔,我迩来用
  1. Laravel
复制代码
  1. Vue 3.0
复制代码
撸了一个博客体系,此中利用到了一个基于markdown-it 的
  1. markdown
复制代码
编辑器Vue组件v-md-editor。我感觉用它去编写
  1. markdown
复制代码
还是很方便的。背面就有了一个想法,基于此组件用Electron来实现一个
  1. markdown
复制代码
桌面端应用,本身平常拿来利用也是个不错的选择。
  1. 题外话:<strong>VS Code</strong>就是用<strong>Electron</strong>开发出来的桌面应用,我现在除了移动端的开发外,其他的都是使用<strong>VS Code</strong>来开发了,各种插件开发起来真的很方便。
复制代码
接下来我就带各人来一步步来实现这个功能。

Vue CLI 搭建Vue项目

在选择的目录下执行
  1. vue create electron-vue3-mark-down
复制代码
选择自界说的模板(可以选择默认的Vue 3 模板)


选择Vue3TypeScript, 其他的选项基于自身项目决定是否选择

执行
  1. npm run serve
复制代码
看看结果


Vue项目改造为markdown编辑器

执行
  1. npm i @kangc/v-md-editor@next -S
复制代码
安装v-md-editor
添加TypeScript类型界说文件
  1. 由于<strong>v-md-editor</strong>这个库没有<strong>TypeScript</strong>类型定义文件,我就直接在<strong>shims-vue.d.ts</strong>这个文件的后面添加的,当然也可以新建一个文件添加申明(<strong>tsconfig.json</strong>能找到这个文件就OK)。
复制代码
  1. declare module "*.vue" {
  2.   import type { DefineComponent } from "vue";
  3.   const component: DefineComponent<{}, {}, any>;
  4.   export default component;
  5. }
  6. <!-- 添加的内容 -->
  7. declare module "@kangc/v-md-editor/lib/theme/vuepress.js";
  8. declare module "@kangc/v-md-editor/lib/plugins/copy-code/index";
  9. declare module "@kangc/v-md-editor/lib/plugins/line-number/index";
  10. declare module "@kangc/v-md-editor";
  11. declare module "prismjs";
复制代码
改造App.vue
  1. <template>
  2.   <div>
  3.     <v-md-editor v-model="content" height="100vh"></v-md-editor>
  4.   </div>
  5. </template>
  6. <script lang="ts">
  7. // 编辑器
  8. import VMdEditor from "@kangc/v-md-editor";
  9. import "@kangc/v-md-editor/lib/style/base-editor.css";
  10. import vuepress from "@kangc/v-md-editor/lib/theme/vuepress.js";
  11. import "@kangc/v-md-editor/lib/theme/style/vuepress.css";
  12. // 高亮显示
  13. import Prism from "prismjs";
  14. import "prismjs/components/prism-json";
  15. import "prismjs/components/prism-dart";
  16. import "prismjs/components/prism-c";
  17. import "prismjs/components/prism-swift";
  18. import "prismjs/components/prism-kotlin";
  19. import "prismjs/components/prism-java";
  20. // 快捷复制代码
  21. import createCopyCodePlugin from "@kangc/v-md-editor/lib/plugins/copy-code/index";
  22. import "@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css";
  23. // 行号
  24. import createLineNumbertPlugin from "@kangc/v-md-editor/lib/plugins/line-number/index";
  25. VMdEditor.use(vuepress, {
  26.   Prism,
  27. })
  28.   .use(createCopyCodePlugin())
  29.   .use(createLineNumbertPlugin());
  30. import { defineComponent, ref } from "vue";
  31. export default defineComponent({
  32.   name: "App",
  33.   components: { VMdEditor },
  34.   setup() {
  35.     const content = ref("");
  36.     return { content };
  37.   },
  38. });
  39. </script>
  40. <style>
  41. /* 去掉一些按钮 */
  42. .v-md-icon-save,
  43. .v-md-icon-fullscreen {
  44.   display: none;
  45. }
  46. </style>
复制代码
  1. 这个文件也很简单,整个页面就是一个编辑器[code]<v-md-editor v-model="content" height="100vh"></v-md-editor>
复制代码
,这个markdown编辑器有高亮表现,代码表现行号,复制代码按钮等插件,当然更方便的是可以添加其他的插件丰富这个markdown编辑器的功能.[/code]结果如下


Vue CLI Plugin Electron Builder

我实验过用Vite 2.0去搭建Electron项目,但是没有找到类似的ViteElectron团结好使的工具,以是放弃了Vite 2.0的诱惑。如果有小同伴有推荐可以分享下。
利用
  1. vue add electron-builder
复制代码
安装,我选择的是13.0.0Electron的最新版本。
  1. 我一般是选择最高的版本,其实这个版本有坑,我后面再想想要不要介绍下这个坑,哈哈。
复制代码
  1. 我们看到新加了很多的依赖库,还添加了一个[code]background.ts
复制代码
文件。简单先容下,这个文件执行在主线程,其他的页面都是在渲染线程。渲染线程有很多限定的,有些功能只能在主线程执行,这里就不详细睁开了。[/code]执行
  1. npm run electron:serve
复制代码
看结果
  1. 至此,就可以看到桌面应用的效果了,并且边修改Vue的代码,桌面应用也能实时看到修改后的效果。
复制代码
优化功能


启动全屏表现

引入screen
  1. import { screen } from "electron";
复制代码
创建窗口的时候设置为screen巨细
  1. <!-- background.ts -->
  2. async function createWindow() {
  3.   const { width, height } = screen.getPrimaryDisplay().workAreaSize;
  4.   const win = new BrowserWindow({
  5.     width,
  6.     height,
  7.     // 省略...
  8.   });
  9.     // 省略...
  10. }
复制代码
  1. 这样应用启动的时候就是全屏显示了。
复制代码
修改菜单栏

界说菜单栏
  1. <!-- background.ts -->
  2. const template: Array<MenuItemConstructorOptions> = [
  3.   {
  4.     label: "MarkDown",
  5.     submenu: [
  6.       {
  7.         label: "关于",
  8.         accelerator: "CmdOrCtrl+W",
  9.         role: "about",
  10.       },
  11.       {
  12.         label: "退出程序",
  13.         accelerator: "CmdOrCtrl+Q",
  14.         role: "quit",
  15.       },
  16.     ],
  17.   },
  18.   {
  19.     label: "文件",
  20.     submenu: [
  21.       {
  22.         label: "打开文件",
  23.         accelerator: "CmdOrCtrl+O",
  24.         click: (
  25.           item: MenuItem,
  26.           focusedWindow: BrowserWindow | undefined,
  27.           _event: KeyboardEvent
  28.         ) => {
  29.             // TODO: 打开文件         
  30.         },
  31.       },
  32.       {
  33.         label: "存储",
  34.         accelerator: "CmdOrCtrl+S",
  35.         click: (
  36.           item: MenuItem,
  37.           focusedWindow: BrowserWindow | undefined,
  38.           _event: KeyboardEvent
  39.         ) => {
  40.           // TODO: 存储内容  
  41.         },
  42.       },
  43.     ],
  44.   },
  45.   {
  46.     label: "编辑",
  47.     submenu: [
  48.       {
  49.         label: "撤销",
  50.         accelerator: "CmdOrCtrl+Z",
  51.         role: "undo",
  52.       },
  53.       {
  54.         label: "重做",
  55.         accelerator: "Shift+CmdOrCtrl+Z",
  56.         role: "redo",
  57.       },
  58.       {
  59.         type: "separator",
  60.       },
  61.       {
  62.         label: "剪切",
  63.         accelerator: "CmdOrCtrl+X",
  64.         role: "cut",
  65.       },
  66.       {
  67.         label: "复制",
  68.         accelerator: "CmdOrCtrl+C",
  69.         role: "copy",
  70.       },
  71.       {
  72.         label: "粘贴",
  73.         accelerator: "CmdOrCtrl+V",
  74.         role: "paste",
  75.       },
  76.     ],
  77.   },
  78.   {
  79.     label: "窗口",
  80.     role: "window",
  81.     submenu: [
  82.       {
  83.         label: "最小化",
  84.         accelerator: "CmdOrCtrl+M",
  85.         role: "minimize",
  86.       },
  87.       {
  88.         label: "最大化",
  89.         accelerator: "CmdOrCtrl+M",
  90.         click: (
  91.           item: MenuItem,
  92.           focusedWindow: BrowserWindow | undefined,
  93.           _event: KeyboardEvent
  94.         ) => {
  95.           if (focusedWindow) {
  96.             focusedWindow.maximize();
  97.           }
  98.         },
  99.       },
  100.       {
  101.         type: "separator",
  102.       },
  103.       {
  104.         label: "切换全屏",
  105.         accelerator: (function () {
  106.           if (process.platform === "darwin") {
  107.             return "Ctrl+Command+F";
  108.           } else {
  109.             return "F11";
  110.           }
  111.         })(),
  112.         click: (
  113.           item: MenuItem,
  114.           focusedWindow: BrowserWindow | undefined,
  115.           // eslint-disable-next-line @typescript-eslint/no-unused-vars
  116.           _event: KeyboardEvent
  117.         ) => {
  118.           if (focusedWindow) {
  119.             focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
  120.           }
  121.         },
  122.       },
  123.     ],
  124.   },
  125.   {
  126.     label: "帮助",
  127.     role: "help",
  128.     submenu: [
  129.       {
  130.         label: "学习更多",
  131.         click: function () {
  132.           shell.openExternal("http://electron.atom.io");
  133.         },
  134.       },
  135.     ],
  136.   },
  137. ];
复制代码
  1. 具体如何定义参阅Electron Menu。
  2. <strong>打开文件</strong>和<strong>存储</strong>目前还没实现,后面实现。
复制代码
设置菜单栏
  1. import { Menu } from "electron";
  2. app.on("ready", async () => {
  3.   // 省略...
  4.   // 创建菜单
  5.   Menu.setApplicationMenu(Menu.buildFromTemplate(template));
  6. });
复制代码
  1. 在[code]ready
复制代码
钩子函数中举行设置Menu。[/code]结果


编辑器打开markdonw文件的内容

主线程选择文件,将文件路径传给渲染线程
  1. <!-- background.ts -->
  2. dialog
  3.   .showOpenDialog({
  4.     properties: ["openFile"],
  5.     filters: [{ name: "Custom File Type", extensions: ["md"] }],
  6.   })
  7.   .then((res) => {
  8.     if (res && res["filePaths"].length > 0) {
  9.       const filePath = res["filePaths"][0];
  10.       // 将文件传给渲染线程
  11.       if (focusedWindow) {
  12.         focusedWindow.webContents.send("open-file-path", filePath);
  13.       }
  14.     }
  15.   })
  16.   .catch((err) => {
  17.     console.log(err);
  18.   });
复制代码
  1. [code]showOpenDialog
复制代码
是打开文件的方法,我们这里指定了只打开md文件;获得文件路径后,通过
  1. focusedWindow.webContents.send("open-file-path", filePath);
复制代码
这个方法将文件路径传给渲染线程。[/code]渲染线程取到文件路径,读取文件内容,赋值给markdown编辑器
  1. <!-- App.vue -->
  2. import { ipcRenderer } from "electron";
  3. import { readFileSync } from "fs";
  4. export default defineComponent({
  5.   // 省略...
  6.   setup() {
  7.     const content = ref("");
  8.    
  9.     onMounted(() => {
  10.       // 1.
  11.       ipcRenderer.on("open-file-path", (e, filePath: string) => {
  12.         if (filePath && filePath.length > 0) {
  13.           // 2.
  14.           content.value = readFileSync(filePath).toString();
  15.         }
  16.       });
  17.     });
  18.     return { content };
  19.   },
  20. });
复制代码
vue添加node支持
  1. <!-- vue.config.js -->
  2. module.exports = {
  3.   pluginOptions: {
  4.     electronBuilder: {
  5.       nodeIntegration: true,
  6.     },
  7.   },
  8. };
复制代码
结果


markdonw的内容存入文件

主线程发起向渲染线程获取编辑器内容的哀求
  1. <!-- background.js -->
  2. if (focusedWindow) {
  3.     focusedWindow.webContents.send("get-content", "");
  4. }
复制代码
渲染线程主线程向返回编辑器的内容
  1. <!-- App.vue -->
  2. onMounted(() => {
  3.     ipcRenderer.on("get-content", () => {
  4.         ipcRenderer.send("save-content", content.value);
  5.     });
  6. });
复制代码
主线程收到内容然后存入文件
  1. <!-- background.ts -->
  2. // 存储文件
  3. ipcMain.on("save-content", (event: unknown, content: string) => {
  4.   if (openedFile.length > 0) {
  5.     // 直接存储到文件中去
  6.     try {
  7.       writeFileSync(openedFile, content);
  8.       console.log("保存成功");
  9.     } catch (error) {
  10.       console.log("保存失败");
  11.     }
  12.   } else {
  13.     const options = {
  14.       title: "保存文件",
  15.       defaultPath: "new.md",
  16.       filters: [{ name: "Custom File Type", extensions: ["md"] }],
  17.     };
  18.     const focusedWindow = BrowserWindow.getFocusedWindow();
  19.     if (focusedWindow) {
  20.       dialog
  21.         .showSaveDialog(focusedWindow, options)
  22.         .then((result: Electron.SaveDialogReturnValue) => {
  23.           if (result.filePath) {
  24.             try {
  25.               writeFileSync(result.filePath, content);
  26.               console.log("保存成功");
  27.               openedFile = result.filePath;
  28.             } catch (error) {
  29.               console.log("保存失败");
  30.             }
  31.           }
  32.         })
  33.         .catch((error) => {
  34.           console.log(error);
  35.         });
  36.     }
  37.   }
  38. });
复制代码
结果


打包

设置应用的名字和图片
  1. <!-- vue.config.js -->
  2. module.exports = {
  3.   pluginOptions: {
  4.     electronBuilder: {
  5.       nodeIntegration: true,
  6.       // 添加的设置
  7.       builderOptions: {
  8.         appId: "com.johnny.markdown",
  9.         productName: "JJMarkDown",  // 应用的名字
  10.         copyright: "Copyright © 2021", //版权声明
  11.         mac: {
  12.           icon: "./public/icon.icns", // icon
  13.         },
  14.       },
  15.     },
  16.   },
  17. };
复制代码
icon.icns生成 预备一个1024*1024的图片,同级目录下创建一个为
  1. icons.iconset
复制代码
的文件夹;
创建各种差别尺寸要求的图片文件
  1. sips -z 16 16 icon.png -o icons.iconset/icon_16x16.png
  2. sips -z 32 32 icon.png -o icons.iconset/icon_16x16@2x.png
  3. sips -z 32 32 icon.png -o icons.iconset/icon_32x32.png
  4. sips -z 64 64 icon.png -o icons.iconset/icon_32x32@2x.png
  5. sips -z 128 128 icon.png -o icons.iconset/icon_128x128.png
  6. sips -z 256 256 icon.png -o icons.iconset/icon_128x128@2x.png
  7. sips -z 256 256 icon.png -o icons.iconset/icon_256x256.png
  8. sips -z 512 512 icon.png -o icons.iconset/icon_256x256@2x.png
  9. sips -z 512 512 icon.png -o icons.iconset/icon_512x512.png
  10. sips -z 1024 1024 icon.png -o icons.iconset/icon_512x512@2x.png
复制代码
获得名为icon.icns的图标文件
  1. iconutil -c icns icons.iconset -o icon.icns
复制代码
打包
  1. npm run electron:build
复制代码
结果

获得的dmg文件就可以直接安装利用了。
代码
  1. <!-- background.ts -->
  2. "use strict";
  3. import {
  4.   app,
  5.   protocol,
  6.   BrowserWindow,
  7.   screen,
  8.   Menu,
  9.   MenuItem,
  10.   shell,
  11.   dialog,
  12.   ipcMain,
  13. } from "electron";
  14. import { KeyboardEvent, MenuItemConstructorOptions } from "electron/main";
  15. import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
  16. import installExtension, { VUEJS3_DEVTOOLS } from "electron-devtools-installer";
  17. const isDevelopment = process.env.NODE_ENV !== "production";
  18. import { writeFileSync } from "fs";
  19. let openedFile = "";
  20. // 存储文件
  21. ipcMain.on("save-content", (event: unknown, content: string) => {
  22.   if (openedFile.length > 0) {
  23.     // 直接存储到文件中去
  24.     try {
  25.       writeFileSync(openedFile, content);
  26.       console.log("保存成功");
  27.     } catch (error) {
  28.       console.log("保存失败");
  29.     }
  30.   } else {
  31.     const options = {
  32.       title: "保存文件",
  33.       defaultPath: "new.md",
  34.       filters: [{ name: "Custom File Type", extensions: ["md"] }],
  35.     };
  36.     const focusedWindow = BrowserWindow.getFocusedWindow();
  37.     if (focusedWindow) {
  38.       dialog
  39.         .showSaveDialog(focusedWindow, options)
  40.         .then((result: Electron.SaveDialogReturnValue) => {
  41.           if (result.filePath) {
  42.             try {
  43.               writeFileSync(result.filePath, content);
  44.               console.log("保存成功");
  45.               openedFile = result.filePath;
  46.             } catch (error) {
  47.               console.log("保存失败");
  48.             }
  49.           }
  50.         })
  51.         .catch((error) => {
  52.           console.log(error);
  53.         });
  54.     }
  55.   }
  56. });
  57. const template: Array<MenuItemConstructorOptions> = [
  58.   {
  59.     label: "MarkDown",
  60.     submenu: [
  61.       {
  62.         label: "关于",
  63.         accelerator: "CmdOrCtrl+W",
  64.         role: "about",
  65.       },
  66.       {
  67.         label: "退出程序",
  68.         accelerator: "CmdOrCtrl+Q",
  69.         role: "quit",
  70.       },
  71.     ],
  72.   },
  73.   {
  74.     label: "文件",
  75.     submenu: [
  76.       {
  77.         label: "打开文件",
  78.         accelerator: "CmdOrCtrl+O",
  79.         click: (
  80.           item: MenuItem,
  81.           focusedWindow: BrowserWindow | undefined,
  82.           // eslint-disable-next-line @typescript-eslint/no-unused-vars
  83.           _event: KeyboardEvent
  84.         ) => {
  85.           dialog
  86.             .showOpenDialog({
  87.               properties: ["openFile"],
  88.               filters: [{ name: "Custom File Type", extensions: ["md"] }],
  89.             })
  90.             .then((res) => {
  91.               if (res && res["filePaths"].length > 0) {
  92.                 const filePath = res["filePaths"][0];
  93.                 // 将文件传给渲染线程
  94.                 if (focusedWindow) {
  95.                   focusedWindow.webContents.send("open-file-path", filePath);
  96.                   openedFile = filePath;
  97.                 }
  98.               }
  99.             })
  100.             .catch((err) => {
  101.               console.log(err);
  102.             });
  103.         },
  104.       },
  105.       {
  106.         label: "存储",
  107.         accelerator: "CmdOrCtrl+S",
  108.         click: (
  109.           item: MenuItem,
  110.           focusedWindow: BrowserWindow | undefined,
  111.           // eslint-disable-next-line @typescript-eslint/no-unused-vars
  112.           _event: KeyboardEvent
  113.         ) => {
  114.           if (focusedWindow) {
  115.             focusedWindow.webContents.send("get-content", "");
  116.           }
  117.         },
  118.       },
  119.     ],
  120.   },
  121.   {
  122.     label: "编辑",
  123.     submenu: [
  124.       {
  125.         label: "撤销",
  126.         accelerator: "CmdOrCtrl+Z",
  127.         role: "undo",
  128.       },
  129.       {
  130.         label: "重做",
  131.         accelerator: "Shift+CmdOrCtrl+Z",
  132.         role: "redo",
  133.       },
  134.       {
  135.         type: "separator",
  136.       },
  137.       {
  138.         label: "剪切",
  139.         accelerator: "CmdOrCtrl+X",
  140.         role: "cut",
  141.       },
  142.       {
  143.         label: "复制",
  144.         accelerator: "CmdOrCtrl+C",
  145.         role: "copy",
  146.       },
  147.       {
  148.         label: "粘贴",
  149.         accelerator: "CmdOrCtrl+V",
  150.         role: "paste",
  151.       },
  152.     ],
  153.   },
  154.   {
  155.     label: "窗口",
  156.     role: "window",
  157.     submenu: [
  158.       {
  159.         label: "最小化",
  160.         accelerator: "CmdOrCtrl+M",
  161.         role: "minimize",
  162.       },
  163.       {
  164.         label: "最大化",
  165.         accelerator: "CmdOrCtrl+M",
  166.         click: (
  167.           item: MenuItem,
  168.           focusedWindow: BrowserWindow | undefined,
  169.           // eslint-disable-next-line @typescript-eslint/no-unused-vars
  170.           _event: KeyboardEvent
  171.         ) => {
  172.           if (focusedWindow) {
  173.             focusedWindow.maximize();
  174.           }
  175.         },
  176.       },
  177.       {
  178.         type: "separator",
  179.       },
  180.       {
  181.         label: "切换全屏",
  182.         accelerator: (function () {
  183.           if (process.platform === "darwin") {
  184.             return "Ctrl+Command+F";
  185.           } else {
  186.             return "F11";
  187.           }
  188.         })(),
  189.         click: (
  190.           item: MenuItem,
  191.           focusedWindow: BrowserWindow | undefined,
  192.           // eslint-disable-next-line @typescript-eslint/no-unused-vars
  193.           _event: KeyboardEvent
  194.         ) => {
  195.           if (focusedWindow) {
  196.             focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
  197.           }
  198.         },
  199.       },
  200.     ],
  201.   },
  202.   {
  203.     label: "帮助",
  204.     role: "help",
  205.     submenu: [
  206.       {
  207.         label: "学习更多",
  208.         click: function () {
  209.           shell.openExternal("http://electron.atom.io");
  210.         },
  211.       },
  212.     ],
  213.   },
  214. ];
  215. protocol.registerSchemesAsPrivileged([
  216.   { scheme: "app", privileges: { secure: true, standard: true } },
  217. ]);
  218. async function createWindow() {
  219.   const { width, height } = screen.getPrimaryDisplay().workAreaSize;
  220.   const win = new BrowserWindow({
  221.     width,
  222.     height,
  223.     webPreferences: {
  224.       nodeIntegration: true,
  225.       contextIsolation: false,
  226.     },
  227.   });
  228.   if (process.env.WEBPACK_DEV_SERVER_URL) {
  229.     // Load the url of the dev server if in development mode
  230.     await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string);
  231.     if (!process.env.IS_TEST) win.webContents.openDevTools();
  232.   } else {
  233.     createProtocol("app");
  234.     // Load the index.html when not in development
  235.     win.loadURL("app://./index.html");
  236.   }
  237. }
  238. // Quit when all windows are closed.
  239. app.on("window-all-closed", () => {
  240.   // On macOS it is common for applications and their menu bar
  241.   // to stay active until the user quits explicitly with Cmd + Q
  242.   if (process.platform !== "darwin") {
  243.     app.quit();
  244.   }
  245. });
  246. app.on("activate", () => {
  247.   // On macOS it's common to re-create a window in the app when the
  248.   // dock icon is clicked and there are no other windows open.
  249.   if (BrowserWindow.getAllWindows().length === 0) createWindow();
  250. });
  251. // This method will be called when Electron has finished
  252. // initialization and is ready to create browser windows.
  253. // Some APIs can only be used after this event occurs.
  254. app.on("ready", async () => {
  255.   if (isDevelopment && !process.env.IS_TEST) {
  256.     // Install Vue Devtools
  257.     try {
  258.       await installExtension(VUEJS3_DEVTOOLS);
  259.     } catch (e) {
  260.       console.error("Vue Devtools failed to install:", e.toString());
  261.     }
  262.   }
  263.   createWindow();
  264.   // 创建菜单
  265.   Menu.setApplicationMenu(Menu.buildFromTemplate(template));
  266. });
  267. // Exit cleanly on request from parent process in development mode.
  268. if (isDevelopment) {
  269.   if (process.platform === "win32") {
  270.     process.on("message", (data) => {
  271.       if (data === "graceful-exit") {
  272.         app.quit();
  273.       }
  274.     });
  275.   } else {
  276.     process.on("SIGTERM", () => {
  277.       app.quit();
  278.     });
  279.   }
  280. }
复制代码
到此这篇关于Vue3和Electron实现桌面端应用详解的文章就先容到这了,更多相关Vue3 Electron 桌面端应用内容请搜索脚本之家从前的文章或继承欣赏下面的相关文章希望各人以后多多支持脚本之家!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作