使用 electron-vue 搭建桌面应用开发模板

参考 PicGo 搭建符合本公司需求的桌面应用开发模板

已实现功能:

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

2.使用 nsis 构建安装向导

3.实现文件的读写功能

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

5.窗口关闭保存到托盘

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

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

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

实现过程:

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

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

2.使用 nsis 构建安装向导

    参考苏南大叔的‘如何利用 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

JS

STYLES

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 插件(基本原理是对 pdf.js 插件进行再次封装)

  •  安装 npm install electron-pdf-window --save-dev
  • 引入 const PDFWindow = require("electron-pdf-window");

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

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

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

你可能感兴趣的:(前端,electron-vue)