Vue+Electron,对官方模板进行改动,并打包为exe文件

#项目地址#美化安装流程#

如果想美化安装流程,需访问以下地址,里面会提供两份二次打包所需代码文件,附带的有额外说明文档!
文章对应的项目地址

1 下载官方模板

注意:修改主进程配置(electron所有配置文件)文件后,需关闭已运行的进程,再启动才会生效,关闭进程再重新启动项目即可看到效果
注意:electron 23 及以上的主版本不再支持Windows 7/8/8.1,如有需要,降低electron版本即可,原文地址: https://www.electronjs.org/zh/blog/windows-7-to-8-1-deprecation-notice
在这里插入图片描述

1.1 安装 Electron

npm install -g electron
  • 为了验证是否安装成功,可以使用如下的命令。
electron --version

1.2 检查镜像源设置

  • electron 有可能存在下载包失败 / 打包时候报下载资源 404、证书失效等等错误,此时需检查npm配置
npm config get
  • 找到以下区域,查看镜像源配置是否正确

disturl = "https://registry.npmmirror.com/-/binary/node"

electron_mirror = "https://registry.npmmirror.com/-/binary/electron/"

ELECTRON_MIRROR = "https://registry.npmmirror.com/-/binary/electron/"

registry = "https://registry.npmmirror.com/"

strict-ssl = false
  • 如果不正确,使用以下方式进行单独修改
npm config set disturl=https://registry.npmmirror.com/-/binary/node

npm config set electron_mirror=https://registry.npmmirror.com/-/binary/electron/

npm config set ELECTRON_MIRROR=https://registry.npmmirror.com/-/binary/electron/

1.3 创建运行项目

  • Electron 官方提供了一个简单的项目,可以执行以下命令将项目克隆到本地。
git clone https://github.com/electron/electron-quick-start
  • 如果下不下来,那么我建议去giteeelectron-quick-start,。会有跟github同步更新的仓库,当然文章对应的项目地址里也会有基础模板,只是不会同步更新
    在这里插入图片描述

在这里插入图片描述

  • 然后在项目中执行如下命令即可启动项目。
npm run start

效果图

2 自定义显示窗口的默认菜单

  • 红框里的默认菜单可能满足不了需求 / 想用中文菜单,那么就来自定义菜单。
    效果图

2.1 创建自定义菜单文件,写入/使用自定义菜单

2.1.1 创建自定义菜单文件,写入自定义菜单

  • 在项目根目录创建menuConfig.js文件
-- menuConfig.js --

// 创建菜单模板
module.exports = {
  // process.platform 是 Node.js 提供的一个全局变量 'darwin':表示 macOS 系统 'win32':表示 Windows 系统 'linux':表示 Linux 系统
  template: [
    {
      label: '文件',
      submenu: [
        {
          label: '打开', accelerator: 'Ctrl+O',
          click () {
            console.log("open")
          }
        },
        { label: '保存' },
        { type: 'separator' },
        { label: '退出', role: 'quit' }
      ]
    },
    {
      label: '编辑',
      submenu: [
        { label: '撤销', role: 'undo' },
        { label: '重做', role: 'redo' },
        { type: 'separator' },
        { label: '剪切', role: 'cut', accelerator: 'CmdOrCtrl+X', },
        { label: '复制', role: 'copy' },
        { label: '粘贴', role: 'paste' },
        { label: '删除', role: 'delete' },
        { type: 'separator' },
        { label: '全选', role: 'selectAll' }
      ]
    },
    {
      label: '查看',
      submenu: [{
        label: '重载',
        accelerator: (function () {
          if (process.platform === 'darwin') {
            return 'Ctrl+Command+A'
          } else {
            return 'F5'
          }
        })(),
        click: function (item, focusedWindow) {
          // if (focusedWindow) {
          //   // 重载之后, 刷新并关闭所有的次要窗体
          //   if (focusedWindow.id === 1) {
          //     BrowserWindow.getAllWindows().forEach(function (win) {
          //       if (win.id > 1) {
          //         win.close()
          //       }
          //     })
          //   }
            focusedWindow.reload()
          // }
        }
      }, {
        label: '切换开发者工具',
        accelerator: (function () {
          // 判断是否是macOS系统
          if (process.platform === 'darwin') {
            return 'Alt+Command+I'
          } else {
            return 'Ctrl+Shift+I'
          }
        })(),
        click: function (item, focusedWindow) {
          if (focusedWindow) {
            focusedWindow.toggleDevTools()
          }
        }
      }, {
        type: 'separator'
      }, {
        label: '应用程序菜单演示',
        click: function (item, focusedWindow) {
          if (focusedWindow) {
            const options = {
              type: 'info',
              title: '应用程序菜单演示',
              buttons: ['好的'],
              message: '此演示用于 "菜单" 部分, 展示如何在应用程序菜单中创建可点击的菜单项.'
            }
            dialog.showMessageBox(focusedWindow, options, function () { })
          }
        }
      }]
    },
    {
      label: '窗口',
      role: 'window',
      submenu: [{
        label: '最小化',
        accelerator: 'CmdOrCtrl+M',
        role: 'minimize'
      }, {
        label: '关闭',
        accelerator: 'CmdOrCtrl+W',
        role: 'close'
      }, {
        type: 'separator'
      }, {
        label: '重新打开窗口',
        accelerator: 'CmdOrCtrl+Shift+T',
        enabled: false, // 是否禁用  false 禁用 true
        key: 'reopenMenuItem',
        click: function () {
          app.emit('activate')
        }
      }]
    },
    {
      label: '帮助',
      submenu: [
        {
          label: '关于', click: function () {
            shell.openExternal('http://electron.atom.io')
          }
        }
      ]
    }
  ],
}

2.1.2 使用自定义菜单

-- main.js --

const { app, BrowserWindow, Menu } = require('electron')
const { template } = require('./menuConfig');

// 创建菜单对象
const menu = Menu.buildFromTemplate(template);

// 设置应用程序菜单
Menu.setApplicationMenu(menu);

效果图
效果图

3 项目运行后展示Vue项目,打包为exe程序

3.1 项目运行后展示Vue项目

  • 将自己的Vue项目打包,并将文件拷贝到electron项目的根目录
-- main.js --
	
  // 我的打包后的文件名叫 vue-dist 根据自己的文件名自行修改
  global.__static = path.join(__dirname, '/vue-dist').replace(/\\/g, '\\\\')
  mainWindow.loadURL(`${global.__static}/index.html`)

效果图
效果图

3.2 开发过程中动态更新页面改动

  • 上面想让electron展示Vue项目只能运行打包后的效果,那么开发过程中想实时看到效果就需要按以下配置
  // global.__static = path.join(__dirname, '/vue-dist').replace(/\\/g, '\\\\')
  // mainWindow.loadURL(`${global.__static}/index.html`)
  
  --  变成 --
  
  // 根据自己的本地地址修改
  mainWindow.loadURL('http://localhost:8001')
  • 现在改动Vue代码,electron也会同步更新,这样正常用网页端去调试代码。

3.3 通过环境变量去区分生产/开发环境

  • app.isPackaged 生产环境 返回true ,否则返回false,那么可以将上边写的配置进行区分
  // 加载应用程序
  if (!app.isPackaged) {
    // 读取文件url地址 - 开发用   生产环境 返回true ,否则返回false 
    mainWindow.loadURL('http://localhost:8001')
  } else {
    // 读取本地文件地址 - 打包用
    global.__static = path.join(__dirname, '/vue-dist').replace(/\\/g, '\\\\')
    mainWindow.loadURL(`${global.__static}/index.html`)
  }

3.4 打包为exe程序

3.4.1 无需安装的exe程序

  • 修改读取资源位置
  // 开发用
  // mainWindow.loadURL('http://localhost:8001')
  
  // 打包用
  global.__static = path.join(__dirname, '/vue-dist').replace(/\\/g, '\\\\')
  mainWindow.loadURL(`${global.__static}/index.html`)
  • *package.json文件自定义打包命令
// electron 打包出来的项目名, platform=win32 windows 系统, --arch=x64 系统版本,  --icon 图标路径, --out打包后输出文件路径, app-version=0.0.1 版本号
"package": "electron-packager . electron --platform=win32 --arch=x64 --icon=./icon/icon.ico --out=./out-dist --asar --app-version=0.0.1 --overwrite --ignore=node_modules"
  "scripts": {
    "start": "electron .",
    "package": "electron-packager . electron --platform=win32 --arch=x64 --icon=./icon/icon.ico --out=./out-dist --asar --app-version=0.0.1 --overwrite --ignore=node_modules"
  },
  • 运行打包命令
npm run package
// 如果报错 Cannot find module 'electron,更新下包即可, 更新后再执行 npm run package
// npm initall
// npm run package
  • 由于electron装的版本不同,对Node版本的限制也不一样,如果Node版本不对,控制台会给出提示,自行升级版本即可。
    效果图
  • 打包后会在项目根目录out-dist/electron-win32-x64中找到已经打包好的exe文件,双击执行即可。

3.4.2 自定义安装的exe程序

  • 上边的无法自定义安装位置,总会觉得不像是个exe程序,那么下边将会描述如何改成双击后执行自定义安装。
  • 在项目根目录创建electron-builder.json文件
{
  "appId": "exe-dome.example.myapp", //  指定应用程序的唯一标识符,通常使用逆域名表示,用于在不同平台上标识应用程序
  "productName": "exe-dist", // 指定生成的安装程序的名称。
  "directories": {
    "output": "exe-dist" // 指定输出目录,即生成的安装程序的存放位置。
  },
  "win": {
    "target": "nsis", // 指定打包的目标格式为 NSIS(Nullsoft Scriptable Install System)安装程序。
    "icon": "./icon/icon.jpg", // 指定应用程序的图标文件路径。
    "artifactName": "${productName} Setup ${version}.${ext}" // 指定生成的安装程序的文件名格式 ${productName} 会被替换为应用程序名称,${version} 会被替换为应用程序版本号,${ext} 会被替换为文件扩展名。
  },
  "nsis": {
    "oneClick": false, // 禁用一键安装模式,用户需要手动选择安装选项。
    "perMachine": true, // 将安装程序安装为所有用户,而不是当前用户。
    "allowToChangeInstallationDirectory": true // 允许用户选择安装目录。
  }
}
  • 下载所需npm包
npm i electron-builder -D
  • package.json文件自定义打包命令
// "build": "electron-builder"
  "scripts": {
    "start": "electron .",
    "package": "electron-packager . electron --platform=win32 --arch=x64 --icon=./icon/icon.ico --out=./out-dist --asar --app-version=0.0.1 --overwrite --ignore=node_modules",
    "build": "electron-builder"
  },
  • 注意:每次打包前建议确认上一次打包出来的文件已被手动删除,如果还存在,那么将其手动删除后再打包
  • 执行自定义安装打包命令
npm run build
  • 打包后在根目录exe-dist文件夹即可找到exe程序,双击执行即可出现安装程序
  • 注意:安装后,此exe程序是真实安装到了电脑上,并会生成注册表文件,需手动卸载。
    效果图

4 由渲染进程Vue来控制主进程electron的,全屏/半屏,最小化,关闭,最小化到系统托盘等。

  • 现在项目的菜单是这个样子的,跟熟知的exe菜单完全不符合,现在希望更加美观,并且更加灵活,那么就需要由界面来控制菜单了。
    效果图

4.1 隐藏窗口的默认菜单

  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    frame: false, // 指定是否显示窗口的默认菜单项。设置为 true 表示显示,默认为 true。
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

效果图

4.1.1 隐藏后效果

效果图

4.1.2 窗口其他配置项

	width: 1200, // 窗口宽度
    height: 600, // 窗口高度
    // minWidth: 800, // 窗口的最小宽度。
    // minHeight:600, // 窗口的最小高度。
    // maxWidth:800, // 窗口的最大宽度。
    // maxHeight:600, // 窗口的最大高度。
    // x: 0, // 窗口的横坐标(以像素为单位),默认为屏幕的中心。
    // y: 0, // 窗口的纵坐标(以像素为单位),默认为屏幕的中心。
    frame: true, // 指定是否显示窗口的默认菜单项。设置为 true 表示显示,默认为 true。
    transparent: false, // 指定窗口是否透明,默认为 false。
    // backgroundColor: 'pink', // 窗口的背景颜色,可以使用颜色名称、HEX 值或 RGB 值进行设置。
    title: "exe", // 窗口的标题,优先级低于加载文件。
    // icon: "./icon/icon.jpg", // 窗口的图标路径。
    show: true, // 指定窗口创建后是否立即显示,默认为 true。
    resizable: true, // 指定窗口是否可以调整大小
    center: true, // 指定窗口是否在屏幕中居中,默认为 true。
    movable: true, // 指定窗口是否可以移动,默认为 true。
    minimizable: true, // 指定窗口是否可以最小化,默认为 true。
    maximizable: true, // 指定窗口是否可以最大化,默认为 true。
    closable: true,//指定窗口是否可以关闭,默认为 true。
    fullscreenable: true, // 指定窗口是否可以进入全屏模式,默认为 true。
    alwaysOnTop: false, // 指定窗口是否始终在其他窗口之上,默认为 false。
    fullscreen: false, // 指定窗口是否可以进入全屏模式,默认为 true -- 会导致最小化/半屏/关闭按钮隐藏。
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }

4.2 向渲染进程Vue暴漏主进程的方法

  • 找到项目根目录的preload.js文件
-- preload.js --

/**
 * The preload script runs before. It has access to web APIs
 * as well as Electron's renderer process modules and some
 * polyfilled Node.js functions.
 *
 * https://www.electronjs.org/docs/latest/tutorial/sandbox
 */
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector)
    if (element) element.innerText = text
  }

  for (const type of ['chrome', 'node', 'electron']) {
    replaceText(`${type}-version`, process.versions[type])
  }
})

const { contextBridge, ipcRenderer } = require("electron")

//向渲染进程(vue)暴露一些属性和方法
contextBridge.exposeInMainWorld('versions', {
  // 最小化 / 最小化到系统托盘
  minimize(val) {
    ipcRenderer.send('minimize', val)
  },
  // 窗口最大化
  windowStatus() {
    ipcRenderer.send('windowStatus')
  },
  // 关闭当前窗口
  closeWin() {
    ipcRenderer.send('closeWin')
  },
})

在这里插入图片描述

4.3 在Vue项目制定自己想要的菜单,执行主进程暴漏的方法

  • 都到Vue了,这个菜单展示形式,样式,展示逻辑等等,岂不是随心所欲的控制,只需在需要的时刻执行主进程暴漏的方法即可。
  • 在Vue项目/src下创建header.vue文件,并引入到App.vue中挂载(我这是示例,写的随意而已。)
  • 效果图
  • header.vue加入以下代码 ------- 此时已添加拖拽窗口方法 css代码中的 -webkit-app-region: drag;-webkit-app-region: no-drag;
<template>
  <div class="header">
    <el-tooltip class="item" effect="dark" content="最小化到系统托盘" placement="bottom">
      <span class="no-drag el-icon-circle-close" @click="addMinimize(false)"></span>
    </el-tooltip>
    <el-tooltip class="item" effect="dark" content="最小化" placement="bottom">
      <span class="no-drag el-icon-minus" @click="addMinimize(true)"></span>
    </el-tooltip>
    <el-tooltip class="item" effect="dark" :content="windowStatus ? '窗口化' : '全屏'" placement="bottom">
      <span class="no-drag" :class="windowStatus ? 'el-icon-copy-document' : 'el-icon-full-screen'" @click="addWindowStatus"></span>
    </el-tooltip>
    <el-tooltip class="item" effect="dark" content="关闭程序" placement="bottom">
      <span class="no-drag el-icon-close" @click="addCloseWin"></span>
    </el-tooltip>
  </div>
</template>
<script>
// 来源根目录  preload.js
const versions = window.versions; // electron 暴漏的主进程事件
export default {
  data () {
    return {
      versions, // 主进程暴漏的事件集合  具体看根目录preload.js文件
      windowStatus: false, // 窗口化   true 全屏  false 窗口化
    };
  },
  mounted () { },
  methods: {
    // 最小化 / 最小化到系统托盘
    addMinimize (stata) {
      // true 最小化 false 最小化到系统托盘
      versions.minimize(stata);
    },
    // 窗口最大化/还原
    addWindowStatus () {
      // 窗口状态切换后 -- 切换图标
      this.windowStatus = !this.windowStatus;
      versions.windowStatus();
    },
    addCloseWin () {
      versions.closeWin();
    },
  },
};
</script>
<style lang="less">
.header {
  background-color: pink;
  text-align: right;
  // 鼠标拖拽
  -webkit-app-region: drag;
  span {
    padding: 5px 0;
    font-size: 20px;
    margin-right: 20px;
    color: red;
  }
}
.no-drag {
  // 禁止拖拽
  -webkit-app-region: no-drag;
}
</style>

效果图

4.4 主进程执行渲染进程触发的事件

4.4.1 最小化窗口/全屏/半屏/关闭当前窗口

-- main.js --

const { ipcMain } = require('electron/main')

let mainWindow
function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    frame: false, // 指定是否显示窗口的默认菜单项。设置为 true 表示显示,默认为 true。
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

// 以下事件来源 preload.js

// 最小化窗口
ipcMain.on('minimize', (ev, val) => {
  // true 最小化 false 最小化到系统托盘
  if (val) {
    mainWindow.minimize();
  } else {
    // mainWindow.hide();
  }
})

// 窗口最大化/还原窗口
ipcMain.on('windowStatus', (ev, val) => {
  // 判断当前窗口状态   true 最大化
  if (mainWindow.isMaximized()) {
    mainWindow.restore(); // 还原窗口大小
  } else {
    mainWindow.maximize(); // 最大化窗口
  }
})

// 关闭当前窗口
ipcMain.on('closeWin', (ev, val) => {
  mainWindow.close();
})

在这里插入图片描述

4.4.2 最小化到系统托盘,并制定小菜单

效果图

ipcMain.on('minimize', (ev, val) => {
  // true 最小化 false 最小化到系统托盘
  if (val) {
    mainWindow.minimize();
  } else {
    // mainWindow.hide();
  }
})

--- 变为 ---

ipcMain.on('minimize', (ev, val) => {
  // true 最小化 false 最小化到系统托盘
  if (val) {
    mainWindow.minimize();
  } else {
    mainWindow.hide();
  }
})
const { app, BrowserWindow, Menu, Tray, shell } = require('electron')

app.whenReady().then(() => {
  let tray = null;
  // 设置最小化到系统托盘后的图标
  tray = new Tray(path.join(__dirname, './icon/icon.jpg'));
  // 设置最小化到系统托盘后的小菜单
  const contextMenu = Menu.buildFromTemplate([
    {
      label: '打开应用', click: () => {
        mainWindow.show();
      }
    },
    {
      label: '项目地址', click: () => {
        shell.openExternal('https://gitee.com/kuxiao-smile/exe-demo');
      }
    },
    { type: 'separator' },
    {
      label: '退出', click: () => {
        app.quit();
      }
    }
  ]);
  // 设置最小化到系统托盘后的悬浮名
  tray.setToolTip('我的应用');
  // 将设置的小菜单 加入菜单模板
  tray.setContextMenu(contextMenu);
  // 系统托盘小图标点击事件
  tray.on('click', () => {
    mainWindow.show(); // 点击系统托盘图标时打开应用程序
  });

  // 创建窗口
  createWindow()

  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

效果图

5 添加浏览器扩展程序

5.1 打开控制台

  • 按键盘 ctrl+shift+I,即可打开控制台,但如果想使用Vue扩展就得进行额外配置

5.2 添加Vue扩展程序

app.whenReady().then(async () => {
  // 创建窗口
  createWindow()

  app.on('activate', async () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
  
  // 判断是否生产环境
  // 读取本地浏览器扩展,并添加到控制台  -- 非必要不要使用,会导致浏览器本来装的扩展文件损坏
  if (!app.isPackaged) { // 开发环境启用 vue-devtools 扩展  /nhdogjmejiglipccpnnnanhbledajbpd/6.5.0_0  / 扩展ID/版本号自行修改
    const vueDevToolsPath = path.join(
      os.homedir(),
      '/AppData/Local/Google/Chrome/User Data/Default/Extensions/nhdogjmejiglipccpnnnanhbledajbpd/6.5.0_0'
    )
    await session.defaultSession.loadExtension(vueDevToolsPath)
  }
})

效果图

6 添加可执行外部脚本

const { execFile } = require('child_process');

app.whenReady().then(async () => {
  // 创建窗口
  createWindow()

  app.on('activate', async () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
  
  // 执行外部脚本处理文件  -- 无需要 - 可注释
  execFile(path.join(__dirname, '/微信多开.bat').replace(/\\/g, '\\\\'), (error, stdout, stderr) => {
    if (error) {
      console.error(`执行批处理文件时出错:${error.message}`);
      return;
    }
    console.log('批处理文件执行成功');
    console.log('标准输出:', stdout);
    console.error('错误输出:', stderr);
  });})

效果图

  • 微信多开内容
// 根据自己的微信路径自行修改,改完把文件后缀改成bat即可
start D:\WeChat\WeChat.exe
start D:\WeChat\WeChat.exe

效果图

  • 31
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值