当前位置:   article > 正文

electron项目模板:如何新建一个vue3+electron项目,并加入基础建设_electron vue模板

electron vue模板

1.使用npm creat vite@latest创建一个vue3项目

具体的选择配置如下:
image.png
并且运行提示的这几个步骤
image.png

2.加入electron

官方参考步骤:https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-first-app
a.安装依赖

npm install electron --save-dev
  • 1

b.创建electron的主入口文件以及添加运行脚本命令
在package.json中增加main告诉electron的主入口文件
添加electron的运行命令为 : npm run start
image.png
创建main.js文件,并写入以下代码(官网代码):

const { app, BrowserWindow } = require('electron')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  })

  // 下面的url为自己启动vite项目的url。
  win.loadURL('http://127.0.0.1:5173/')
  // 打开electron的开发者工具
  win.webContents.openDevTools({ mode: 'detach' })
}

app.whenReady().then(() => {
  createWindow()
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

运行npm run start就能成功的运行起你的第一个electron项目了。
image.png
注意,此时你的vite项目应该也是要在运行状态下的,win.loadURL('http://127.0.0.1:5173/')),其中的url就是你运行vite项目的url。相当于此时我们运行了两个项目,一个是electron项目,一个是vite的项目,然后electron相当于就是一个window/mac窗口,然后把网址塞到了这个窗口里面。后期上线就是把开发时的url地址换成已经上线的url地址就行了。
image.png
此时会有一个报错:
原因:是electron安全策略的设置告警,意思是内容安全策略没有设置,或者使用了unsafe-eval的安全设置
解决方法:https://blog.csdn.net/hwytree/article/details/121287531
image.png
我们到index.html中加入下面这个meta即可解决:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline';">
  • 1

3.加入electron预加载脚本,并通过其进行electron和vue的交互

注意:这里你一定要深刻理解这个预加载脚本的作用,否则你会对这个预加载脚本感到很疑惑。这里解释一下这个预加载脚本的作用,
概念理解:
主进程:指的是你的electron进程
预加载脚本:electron进程与vue项目通信的直接桥梁
渲染进程:就是你的vue项目或者react项目
根据electron官网(https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload)所说的,为了安全以及隔离环境,渲染进程与主进程之间的通信需要通过一个preload.js来进行。(总的来说这个preload.js的作用就是作为渲染进程与主进程之间的通信桥梁,做的事就是:1. 给渲染进程(可以说是你src下面的.vue文件和.js文件)暴露方法供渲染进程调用 2.渲染进程调用该方法,该方法中可以给主进程发送事件,然后在主进程中一般会监听该事件,再调用electron的api来改变应用的状态(比如改变窗口的外壳大小,让窗口最小化))

a.在src同级目录建立preload文件夹,下面写index.js,加入以下代码:
const { contextBridge, ipcRenderer } = require('electron')
const handleSend = async (vue_params) => {
  let fallback = await ipcRenderer.invoke('sent-event', vue_params)
  return fallback
}
contextBridge.exposeInMainWorld('myApi', {
  handleSend: handleSend
  // 能暴露的不仅仅是函数,我们还可以暴露变量
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

image.png

b.在main.js中引入预加载脚本,并且添加主进程的监听事件:
 webPreferences: {
      preload: path.join(__dirname, './preload/index.js')
    }
  • 1
  • 2
  • 3
ipcMain.handle('sent-event', (event,params) => {
  console.log(params)
  return '1111'
})
  • 1
  • 2
  • 3
  • 4

image.png

c.在vue中调用,可以看到主进程给我们返回的结果
import { onMounted } from 'vue'
onMounted(async () => {
  let res = await window.myApi.handleSend('liaoruiruirurirui')
  console.log(res)
})
  • 1
  • 2
  • 3
  • 4
  • 5

image.png
image.png
说明:这里主要是告诉大家怎么去引入electron的预加载脚本以及一个简单的使用。具体的通信过程大家可以参考这篇文章:https://blog.csdn.net/weixin_43239880/article/details/129563632?spm=1001.2014.3001.5501
也可以看下官网的教程:https://www.electronjs.org/zh/docs/latest/tutorial/ipc

d.处理ts的报错:在env.d.ts中加入以下代码:
declare interface Window {
  myApi: any
}
  • 1
  • 2
  • 3

image.png
此时我们已经成功的创建了一个vite+vue3+electron的项目!!!

4.优化开发体验

因为此时我们修改vue代码,vite会帮我们热重启。但是当我们修改electron文件的代码时,并没有脚手架帮我们热重启,所以此时我们需要添加nodemon,帮我们重启一下。
a.安装nodemon依赖:

npm i nodemon -D
  • 1

在package.json中的scripts添加这句话进行启动electron项目,nodemon在检测到有以.js,.html结尾文件发生变动时,就会重启窗口(如果需要改变.vue和.css的时候同时启动,也可以继续往后面加,但是没必要,因为这些文件改变,vite会自动热重启。)

"start": "nodemon --exec electron . --watch ./ --ext .js,.html"
  • 1

image.png

5.为vite项目添加一些开发必备的工具

如:添加commitLint,加入element-plus,配置别名,配置代理,添加axios及封装,添加pinia等
如何添加请查看这篇博客,每一步都有详细的步骤和用法。这里就不细说了。

6.系統托盘

指的是这个,如图:
image.png
基本上的桌面端项目都有托盘,所以这里也就写出来了一个简易版本的。大家可以参考一下:
a.在src同级目录新建一个controller目录,在里面建一个tray.js文件,

// 创建系统托盘
const { Tray, Menu } = require('electron')
// const { ipcRenderer } = require('electron')
const path = require('path')

function createTray(app, win) {
  let tray = new Tray(path.join(__dirname, '../public/favicon.ico'))
  // if (process.env.NODE_ENV === 'development') {
  // tray = new Tray(path.join(__dirname, '../public/favicon.ico'))
  // } else {
  // tray = new Tray(path.join(path.dirname(app.getPath('exe')), '/resources/public/logo.ico'))
  // }
  tray.setToolTip('示例平台') // 鼠标放在托盘图标上的提示信息
  tray.on('click', (e) => {
    if (e.shiftKey) {
      app.quit()
    } else {
      win.show()
    }
  })
  tray.setContextMenu(
    Menu.buildFromTemplate([
      {
        label: '退出',
        click: () => {
          // 先把用户的登录状态和用户的登录信息给清楚掉,再退出
          app.quit()
        }
      }
    ])
  )
}
module.exports = createTray

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

image.png
b.在main.js中导入并且使用改函数用来创建托盘。
image.png

6.自定义窗口(不使用原生的窗口)

为什么需要自定义窗口?原因是因为原生的窗口不好看,很难看。且无法去修改,导致满足不了UI的效果,所以很多桌面程序都是自定义窗口。
这里主要是在main.js中创建窗口的时候加入

const win = new BrowserWindow({
    width: 800,
    height: 600,
    frame: false, // 不要自带的窗口
    webPreferences: {
      preload: path.join(__dirname, './preload/index.js')
    }
  })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

image.png
此时我们的程序就变成了这样,看起来很丑陋,但是我们脱离了原生窗口的限制,可以随意发挥了:
image.png

这里的事件主要是运用了渲染进程与主进程之间的通信,简单说一下把:
在HomeView.vue中修改样式,并给每个按钮绑定事件,这个事件需要去调用预加载脚本中导出的事件。

<script setup lang="ts">
// import TheWelcome from '../components/TheWelcome.vue'
import { onMounted } from 'vue'
onMounted(async () => {
  let res = await window.myApi.handleSend('liaoruiruirurirui')
  console.log(res)
})
const toMin = () => {
  window.myApi.windowMin()
}
const toBig = () => {
  window.myApi.windowMax()
}
const toClose = () => {
  window.myApi.windowClose()
}
</script>

<template>
  <main>
    <div class="hearder">
      <span @click="toMin">最小化</span>
      <span @click="toBig">最大化</span>
      <span @click="toClose">关闭</span>
    </div>
    <div class="main">主要内容</div>
    <!-- <TheWelcome /> -->
  </main>
</template>

<style scoped>
.hearder {
  -webkit-app-region: drag;
  background-color: #ccc;
  height: 40px;
  width: 100%;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.hearder span {
  margin: 0 16px;
  border: 1px solid rgb(35, 34, 34);
  cursor: pointer;
  -webkit-app-region: no-drag;
}
.main {
  height: calc(100vh - 40px);
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

细节:窗口顶部可拖动是因为加了这个样式:-webkit-app-region: drag。但是又因为这个样式导致了按钮的点击事件无法响应,所以我们要给按钮加入 -webkit-app-region: no-drag;这个样式。
简单样式为:
image.png
然后我们去预加载脚本中添加事件(添加的事件全都是给主进程发送一个事件的):

const { contextBridge, ipcRenderer } = require('electron')
const handleSend = async (vue_params) => {
  let fallback = await ipcRenderer.invoke('sent-event', vue_params)
  return fallback
}

contextBridge.exposeInMainWorld('myApi', {
  handleSend: handleSend,
  // 能暴露的不仅仅是函数,我们还可以暴露变量
   // 最小化
   windowMin: () => {
    ipcRenderer.send('window-min')
  },
  // 最大化
  windowMax: () => {
    ipcRenderer.send('window-max')
  },
  // 关闭窗口
  windowClose: () => {
    ipcRenderer.send('window-close')
  },
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在controller文件夹中创建changeWindowSize.js文件,加入以下代码,并在主进程的main.js中导入:
这里的代码,其实就是在主进程中调用electron的事件。因为在渲染进程中无法使用electron的东西,所以需要通过预加载脚本来发送事件,主进程监听到了这个事件并作出了相应的回应。

const { ipcMain, BrowserWindow } = require('electron')
// 最小化
ipcMain.on('window-min', event => {
  const webContent = event.sender
  const win = BrowserWindow.fromWebContents(webContent)
  win.minimize()
})

// 最大化
ipcMain.on('window-max', event => {
  const webContent = event.sender
  const win = BrowserWindow.fromWebContents(webContent)
  if (win.isMaximized()) {
    win.restore()
  } else {
    win.maximize()
  }
})

// 关闭
ipcMain.on('window-close', event => {
  const webContent = event.sender
  const win = BrowserWindow.fromWebContents(webContent)
  win.close()
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

image.png
image.png

7.基础开发

基础开发这里就不说了,每个人都不同,主要就是利用进程间的通信,不懂的看这篇博客或者官网。把框架搭好之后,根据自己的业务开发就行。
另外提一下就是开发时也要利用electron的apihttps://www.electronjs.org/zh/docs/latest/api/crash-reporter
image.png

8.项目打包:使用electron-builder

a.安装依赖:
npm install electron-builder -D
  • 1
b.在package.json中进行配置

配置项信息具体看官方文档:https://www.electron.build/configuration/configuration
也可以看这篇博客:https://juejin.cn/post/6844903693683261453#comment
这里我就直接贴我们这边的配置了(这个build和scripts同级)

"build": {
    "appId": "com.police.desktop",//包名  
    "productName": "测试平台", //项目名 这也是生成的exe文件的前缀名
    "asar": true,
    "copyright": "Copyright © 2022 electron",//版权  信息
    "publish": {
      "provider": "generic",// 服务器提供商 也可以是GitHub等等
      "url": ""// 服务器地址
    },
    "directories": { // 输出文件夹
      "output": "electron-build/"
    },
    "extraResources": [
      {
        "from": "./public",
        "to": "./public"
      }
    ],
    "files": [ // 打包的electron需要包含的文件,一般就是与electron的有关的打包进去
      "main.js", // electron主入口文件
      "controller", // 也是主入口文件,只不过拆成了两个文件
      "preload" //预加载文件
    ],
    "mac": {
      "artifactName": "${productName}_${version}.${ext}",
      "target": [
        "dmg"
      ]
    },
    "win": {
      "icon": "public/logoTemplate.ico",
      "target": [
        {
          "target": "nsis",
          "arch": [
            "ia32"
          ]
        }
      ],
      "artifactName": "${productName}_${version}.${ext}"
    },
    "nsis": {
      "oneClick": false,// 是否一键安装
      "perMachine": false,
      "allowToChangeInstallationDirectory": true,// 允许修改安装目录
      "deleteAppDataOnUninstall": false,
      "installerIcon": "public/favicon.ico",// 安装图标
      "uninstallerIcon": "public/favicon.ico",// 创建桌面图标
      "createDesktopShortcut": true,// 创建桌面图标
      "createStartMenuShortcut": true,// 创建开始菜单图标
      "shortcutName": "测试平台" // 图标名称
    },
    "releaseInfo": {
      "releaseNotes": "版本更新的具体内容"
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
c.进行打包,使用命令:npm run app:dist

在package.son中加入运行命令:

"app:dist": "electron-builder"
  • 1

image.png

d.解决打包时因为网络导致下载包失败的问题。

可以看我的另一篇博客:https://blog.csdn.net/weixin_43239880/article/details/129532978?spm=1001.2014.3001.5502
image.png
登录这个网站:https://registry.npmmirror.com/binary.html?path=electron/24.1.3/,找到对应的包,下载下来
image.png
放到路径下:C:\Users\DELL\AppData\Local\electron\Cache(这是我电脑的路径,你的路径请根据博客内容自己去看下在哪里)
image.png
再次运行即可打包成功。
image.png
image.png

9.解决托盘打包之后消失的问题:

此时我们就能看到我们的桌面项目正常运行了,但是,会发现右下角的托盘运行的时候有占位,但是却没有图片在上面!!!!
image.png
请看这篇文章,有详细的解决步骤:https://blog.csdn.net/weixin_43239880/article/details/129495602?spm=1001.2014.3001.5502

10.打包vite项目,并将项目上线

运行命令:

npm run build
  • 1

image.png
将vite项目打包后的dist文件上线。将main.js中的url改成把上线后的ip地址
image.png
如何将项目上线?
请查看我这篇博客:https://blog.csdn.net/weixin_43239880/article/details/129434402?spm=1001.2014.3001.5501

其他:

项目模板地址:https://github.com/rui-rui-an/how_to_create_electron_vue

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/905466
推荐阅读
相关标签
  

闽ICP备14008679号