参考 PicGo <https://github.com/Molunerfinn/PicGo> 搭建符合本公司需求的桌面应用开发模板

已实现功能:



1.单行命令即可生成可安装程序

2.使用 nsis 构建安装向导

3.实现文件的读写功能

4.窗口的最小化按钮和关闭按钮以及标题栏自定义,不使用 electron 自身携带的原生标题栏

5.窗口关闭保存到托盘

6.托盘右键菜单有'关于本产品'...菜单

7.使用说明可在独立窗口中打开,且是以本地 pdf 形式

8.使用 nsis 制作安装向导,实现证书自动安装

实现过程:

1.单行命令即可生成可安装程序

    构建项目的时候选择 electron-builder ,执行 npm run build 之后自动打包成 setup.exe 可安装文件


2.使用 nsis 构建安装向导



    参考苏南大叔 <https://newsn.net/say/electron-nsis.html>的‘如何利用 nsis 制作 electron
的安装包’即可,electron-builder 插件也有 nsis 配置项,但是局限性有点大且不可控

3.实现文件的读写功能
// 在 js 中定义 files 读写文件 import path from "path"; import fs from "fs-extra";
import { app, remote } from "electron"; // 引入remote模块 const APP = process.type
=== "renderer" ? remote.app : app; // 根据process.type来分辨在哪种模式使用哪种模块 const
STORE_PATH = APP.getPath("userData"); // 获取electron应用的用户目录 if
(!fs.pathExistsSync(STORE_PATH)) { // 如果不存在路径 fs.mkdirpSync(STORE_PATH); // 就创建
} export const files = { read: function(filesName) { const path_ =
path.join(STORE_PATH, filesName); let filesData = fs.readFileSync(path_,
"utf-8", function(e, data) { if (e) throw e; return data; }); return filesData;
}, write: function(filesName, writeStr) { const path_ = path.join(STORE_PATH,
filesName); fs.open(path_, "w", function(e, fd) { if (e) throw e; fs.write(fd,
writeStr, 0, "utf8", function(e) { if (e) throw e; fs.closeSync(fd); }); }); }
};
调用:
import { files } from "@/scripts/fileOpera.js"; const { ipcRenderer } =
window.require("electron") export default { name: "landing-page", data() {
return { filesData:'' }; }, methods: { writeFile: function() { // 写入
userSet.txt 文件 files.write( "/userSet.txt", 'write some to test' ); },
readFile: function() { // 读取 userSet.txt 文件 this.filesData =
files.read("/userSet.txt"); }, openUseDirections: function(){ // render 进程与
main 进程交互打开使用说明窗口 ipcRenderer.send("openUseDirections"); } } };
4.窗口的最小化按钮和关闭按钮以及标题栏自定义,不使用 electron 自身携带的原生标题栏

    首先在创建窗口的时候需要把 frame 配置项设置为 false,其次在 App.vue 组件中自定义标题栏以及右侧按钮

HTML
<template> <div id="app"> <div class="fake-title-bar"> <div
class="title-mark"> <img src="../../static/menubar-nodarwin.png" /> 标题 </div>
<div class="handle-bar" v-if="os === 'win32'"> <Icon type="minus"
@click="minimizeWindow"></Icon> <Icon type="close" @click="closeWindow"></Icon>
</div> </div> <router-view></router-view> </div> </template>
JS
<script> import { remote } from "electron"; import { myMixin } from
'./mixins/test' const { BrowserWindow } = remote; import {time_differ,
toISOString, formatDate} from '@/scripts/times.js' export default { name:
"buildertest", mixins: [myMixin], data() { return { os: "" }; }, created() {
this.os = process.platform; }, methods: { minimizeWindow() { const window =
BrowserWindow.getFocusedWindow(); window.minimize(); }, closeWindow() { const
window = BrowserWindow.getFocusedWindow(); window.close(); } } }; </script>
STYLES
<style lang='less'> #app { .fake-title-bar { -webkit-app-region: drag; height:
h = 24px; color: #2c2c2c; font-size: 12px; line-height: h; width: 100%;
border-bottom: 1px solid #d8d8d8; position: fixed; z-index: 100; .title-mark {
position: absolute; left: 4px; top: 0; z-index: 10000; padding-left: 26px; img
{ position: absolute; top: 50%; left: 4px; transform: translateY(-50%); height:
20px; } } .handle-bar { position: absolute; top: 2px; right: 4px; width: 40px;
height: h; z-index: 10000; -webkit-app-region: no-drag; i { cursor: pointer;
font-size: 16px; } .ivu-icon-minus { margin-right: 6px; &:hover { color:
#409EFF; } } .ivu-icon-close { &:hover { color: #F15140; } } } } .writeFile {
position: absolute; top: 40px; font-size: 14px; } } </style>
5.窗口关闭保存到托盘

6.托盘右键菜单有'关于本产品'...菜单
// 定义 isQuit 变量存储当前关闭是窗口触发还是右键托盘退出菜单触发 let isQuit = false; // 默认是从窗口触发 //
创建托盘菜单 function createTray() { const menubarPic = process.platform === "darwin"
? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`; tray = new
Tray(menubarPic); contextMenu = Menu.buildFromTemplate([ { label: "关于", click()
{ dialog.showMessageBox({ title: "xxx", message: "xxx", detail: `版本:
${pkg.version}\n` }); } }, { label: "打开", click() { if (mainWindow === null) {
createWindow(); mainWindow.show(); mainWindow.maximize(); } else {
mainWindow.show(); mainWindow.maximize(); } } }, { label: "退出", click:
function() { isQuit = true; app.quit(); app.quit(); //
程序设定关闭为最小化,所以调用两次关闭,防止最大化时一次不能关闭 } } ]); // 设置此托盘图表的悬停提示内容
tray.setToolTip("xxx产品名称"); tray.on("right-click", () => {
tray.popUpContextMenu(contextMenu); }); tray.on("click", () => { if (mainWindow
=== null) { createWindow(); mainWindow.show(); mainWindow.maximize(); } else {
mainWindow.show(); mainWindow.maximize(); } }); } // 监听关闭事件
mainWindow.on("close", function(event) { if (!isQuit) { event.preventDefault();
mainWindow.hide(); } return false; }); // 点击图标(桌面快捷方式)检查当前活动实例的个数 const
isSecondInstance = app.makeSingleInstance(() => { if (mainWindow) { if
(mainWindow.isMinimized()) { mainWindow.restore(); // 窗口从最小化恢复时触发 }
mainWindow.show(); mainWindow.maximize(); mainWindow.focus(); } }); if
(isSecondInstance) { app.quit(); }
7.使用说明可在独立窗口中打开,且是以本地 pdf 形式
// 定义 useDirection 存储使用说明窗口实例 let useDirection = null; // 使用 ipcMain 与
ipcRender 交互 ipcMain.on("openUseDirections", (event) => { let path_ =
app.getAppPath().split("\\").join("/"); if(path_.indexOf("app.asar") !== -1){
// 将目录最后的 /app.asar 去除 path_ = path_.substr(0,path_.lastIndexOf('/')) }
Menu.setApplicationMenu(null);//隐藏菜单 if (useDirection) { if
(useDirection.isMinimized()) { useDirection.restore(); // 窗口从最小化恢复时触发 }
useDirection.show(); useDirection.focus(); }else{ let options = { width: 838,
height: 600, icon:`${__static}/icon.ico`, title:'xxx', autoHideMenuBar:true,
webPreferences: { plugins: true } }; useDirection = new PDFWindow(options);
useDirection.loadURL(`file:///${path_}/static/xxx.pdf`); }
useDirection.on('closed', () => { useDirection = null; })
event.sender.returnValue = false; })
说明:

1) app.getAppPath ()返回当前应用所在的路径,使用 electron-builder 打包的安装程序安装之后返回的路径后面带有
/app.asar 这一结尾路径,需要将此路径去除在重新组合 static/xxx.pdf 路径,因 electron-builder 打包的文件全部是
asar 文件,可以自己写脚本在打包之后新建 static 文件夹,将 xxx.pdf 拷贝进该文件夹,也可手动操作。



2.)新建打开本地 pdf 文件的窗口使用了  electron-pdf-window
<https://github.com/gerhardberger/electron-pdf-window> 插件(基本原理是对 pdf.js
插件进行再次封装)



*  安装 npm install electron-pdf-window --save-dev
* 引入 const PDFWindow = require("electron-pdf-window");
8.使用 nsis 制作安装向导,实现证书自动安装


因本公司自己的产品在客户端安装之后需要安装本公司自己签发的 rootCA.crt 证书,所以在使用 nsis 制作安装向导的时候将执行 run.bat
脚本(安装当前目录的 rootCA.crt 证书到'受信任的根证书颁发机构')



* 使用苏南大叔 <https://newsn.net/say/electron-nsis.html>的‘如何利用 nsis 制作 electron
的安装包’制作安装向导
* 将 run.bat 脚本和 rootCA.crt 证书都拷贝到 resources/static 目录下即可
* 在 Section "MainSection" SEC01 脚本的最后 SectionEnd 脚本的前面添加  ExecShell "open"
"$INSTDIR/resources/static/run.bat"

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信