最近接收了一个三四年前做的项目。主要技术栈就是vue2+electron+sqllite3+node-gyp。看到这个技术栈,基本可以知道感知这个项目的关键词:vue、Gis地图、本地数据库、桌面客户端。顿时深感亚历山大。
不多说,开干。
第一步,查看项目
我一般喜欢直接看一个项目用了哪些东西。然后再慢慢去看具体细节。以上就是这个项目的用到的依赖。首先我们需要下载下来,安装依赖看看。
第二步,升级项目
之前项目用的node 10。而且脚手架和很多依赖版本太低。所以需要对项目做个整容手术。
我的node环境是14。版本不算高。因为公司大多项目很老,贸然升级,下力不讨好。
直接install。
果然不出所料,直接报错。
报错卡在了sqllite3、node-gyp的安装上,大概意思就是没有VC++环境。
行吧,既然这样我在电脑上开始安装VC。
地址:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具
需注意:下载的时候,需要勾选C++客户端开发这个包,否则就白瞎了。
安装成功后,当然还是不行。还要安装python(python安装很简单,自行搜索)。
再次install,终于报错了!!!
electron相关的包完全拉不下来(外网禁止访问)。真是心累。
这里配置electron优点繁琐。有需要可以参考我的另外一篇文章。
vuecli4 electron13.3.0 创建客户端应用以及安装、打包时候遇到的问题_win.loadurl('app://./index.html')_屋昂仼的博客-CSDN博客
索性,我把之前的electron的项目拿过来。两者node_moudules已合并,就齐活了。
npm run electron:dev。
终于又报错了!!
因为之前的项目用的electron的配置文件版本低,有些不适合。所以我再src下直接新建一个background.js, 重新将配置写了一份,并且添加了退出、进入全屏,配置IP端口、打开开发者工具等跨界键和出发事件,整体代码如下:
// background.js
// electron 配置文件
import {
app,
BrowserWindow,
Menu,
MenuItem,
ipcMain,
globalShortcut
} from 'electron'
import {
appMenuTemplate
} from './electron_app/appmenu.js'
import {
createProtocol
} from 'vue-cli-plugin-electron-builder/lib'
/**
* Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
let path = require('path');
let mainWindow
// http://localhost:9080
// const winURL = process.env.NODE_ENV === 'development' ?
// `http://localhost:9080` :
// `file://${__dirname}/index.html`
async function createWindow() {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
// process.env.ELECTRON_NODE_INTEGRATION
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
preload: path.join(__dirname, './preload.js')
},
})
// BrowserWindow.addDevToolsExtension('F:/SC/vue/vue-devtools-5.0.0-beta.3/shells/chrome')
//mainWindow.loadURL(winURL)
mainWindow.on('closed', () => {
mainWindow = null
})
// 渲染以及控制 web 页面
// 屏蔽拖入文件浏览器自动打开事件
mainWindow.webContents.on('will-navigate', function (event) {
event.preventDefault()
})
/**
* 菜单
*/
console.info(appMenuTemplate)
// 增加主菜单(在开发测试时会有一个默认菜单,但打包后这个菜单是没有的,需要自己增加)
const menu = Menu.buildFromTemplate(appMenuTemplate)
// 从模板创建主菜单
// 在File菜单下添加名为New的子菜单
menu.items[0].submenu.append(new MenuItem({ // menu.items获取是的主菜单一级菜单的菜单数组,menu.items[0]在这里就是第1个File菜单对象,在其子菜单submenu中添加新的子菜单
label: 'Open Data',
click() {
mainWindow.webContents.send('action', 'openkml') // 点击后向主页渲染进程发送“新建文件”的命令
},
accelerator: 'CmdOrCtrl+N' // 快捷键:Ctrl+N
}))
menu.items[0].submenu.append(new MenuItem({
role: 'quit'
}))
Menu.setApplicationMenu(menu) // 注意:这个代码要放到菜单添加完成之后,否则会造成新增菜单的快捷键无效
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
// win.loadURL('app://./index.html');
mainWindow.loadURL(path.join(__dirname, './index.html'));
//mainWindow.webContents.openDevTools()
}
//进入软件即开启全屏
mainWindow.setFullScreen(true);
// 最大化
mainWindow.maximize();
//配置ESC键退出全屏
globalShortcut.register('ESC', () => {
mainWindow.setFullScreen(false);
})
// ctrl_alt_S 打开地图服务设置
globalShortcut.register('Alt+CommandOrControl+S', () => {
mainWindow.webContents.send("asynchronous-message", "123");
})
// ctrl_alt_f 打开全屏设置
globalShortcut.register('Alt+CommandOrControl+F', () => {
mainWindow.setFullScreen(true);
})
// 主进程缩小窗口
ipcMain.on('window-min', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
mainWindow.minimize();
})
// 手动打开开发者工具
ipcMain.on('open-dev', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
mainWindow.webContents.openDevTools({
mode: 'bottom'
})
})
// 清楚缓存刷新
ipcMain.on('force-refresh', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
mainWindow.webContents.reloadIgnoringCache()
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
// 监听与渲染进程的通信(暂时无用)
ipcMain.on('reqaction', (event, arg) => {
switch (arg) {
case 'exit':
// 做点其它操作:比如记录窗口大小、位置等,下次启动时自动使用这些设置;不过因为这里(主进程)无法访问localStorage,这些数据需要使用其它的方式来保存和加载,这里就不作演示了。这里推荐一个相关的工具类库,可以使用它在主进程中保存加载配置数据:https://github.com/sindresorhus/electron-store
// ...
app.quit() // 退出程序
break
}
})
/**
* Auto Updater
*
* Uncomment the following code below and install `electron-updater` to
* support auto updating. Code Signing with a valid certificate is required.
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
*/
/*
import { autoUpdater } from 'electron-updater'
autoUpdater.on('update-downloaded', () => {
autoUpdater.quitAndInstall()
})
app.on('ready', () => {
if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
*/
如上,齐活。
这还不够,需要在vue.config.js中配置相关的打包机制。代码如下:
// vue.config.js
// 配置electron打包
// 注意 我只写electron打包的部分 其他的和vue开发相同,不在赘述
// ....
// 添加electron - app -icon
pluginOptions: {
electronBuilder: {
builderOptions: {
productName: 'aaaa', //项目名,也是生成的安装文件名
//copyright: "Copyright © 2023",//版权信息
win: {
icon: './public/aaa.ico',
target: [{
target: "nsis", //利用nsis制作安装程序
arch: [
"x64", //64位
]
}]
},
nsis: {
oneClick: false, // 是否一键安装
allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
allowToChangeInstallationDirectory: true, // 允许修改安装目录
installerIcon: "./public/aaa.ico", // 安装图标
uninstallerIcon: "./public/aaa.ico", //卸载图标
installerHeaderIcon: "./public/aaa.ico", // 安装时头部图标
createDesktopShortcut: true, // 创建桌面图标
createStartMenuShortcut: true, // 创建开始菜单图标
shortcutName: "aaa", // 图标名称
},
directories: {
output: "./aaa" //输出文件路径
},
// 自动更新目录
publish: [{
provider: "generic",
url: "http://192.0.xx.xx:8080/", //隐藏版本服务器地址
}],
},
externals: ['clipboard'],
nodeIntegration: true
}
},
这下终于放心了。
开始启动 npm run electron:dev。
终于成功。一切竟是如此美妙。
第三步,改造项目
里边用到了Arcgis。所以需要使用arcgis的地图服务,包含瓦片、影像、航拍服务等。
这里的地址直接去arcgis里边配置就可以,arcgis是收费软件,所以做的也很傻瓜。
这里需要注意就是我们需要动态配置地图服务。
在backgroundjs中我们加了一个快捷键叫 ctrl+alt+s。 这是用来打开地图IP配置界面的。相应的我们在前端也要写一个配置窗口,界面如下:
界面启动之后,按下CTRL+ALT+S就可以开启。
这个配置界面的代码如下:
// vue 配置窗口文件
<!-- 设置地图服务IP -->
<el-dialog
:close-on-click-modal="false"
title="设置"
:visible.sync="setVisible"
append-to-body>
<el-form>
<el-form-item label="ArcGis的IP和端口, 比如 http://172.17.11.124:8080 ">
<el-input
clearable
v-model="ARC_URL"
placeholder="请输入ArcGis的IP和端口">
</el-input>
</el-form-item>
<el-form-item label="影像地址">
<el-input
clearable
v-model="YX_URL"
placeholder="请输入影像地址">
</el-input>
</el-form-item>
<el-form-item label="航拍地址">
<el-input
clearable
v-model="HP_URL"
placeholder="请输入航拍地址">
</el-input>
</el-form-item>
</el-form>
<!-- 确定按钮 -->
<span slot="footer" class="dialog-footer">
<el-button
type="success"
@click="openDevTools"
>打开开发者工具</el-button>
<el-button
type="primary"
@click="handleClick"
>保存设置</el-button>
<el-button @click="handleConcel">取消</el-button>
</span>
</el-dialog>
对应的方法和数据自行去写,不再赘述。
这里再写一下vue内部和electron之间的通信,比如打开开发者工具和保存设置刷新界面都需要通知electron采取相应的动作:
// vue 中打开开发者工具 和 刷新界面
// 通过 ipcrender 通知electron
// 打开开发者工具
openDevTools () {
ipcRenderer.send('open-dev');
this.setVisible = false;
},
// 刷新界面
reloadPage () {
ipcRenderer.send('force-refresh');
}
// background js
// electron 中接收这个信号
// 手动打开开发者工具
ipcMain.on('open-dev', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
mainWindow.webContents.openDevTools({
mode: 'bottom'
})
})
// 清楚缓存刷新
ipcMain.on('force-refresh', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
mainWindow.webContents.reloadIgnoringCache()
})
一发一收,很方便。
最后,有问题有报错不要怕,一步一步去解决就好。在此,强烈推荐bing搜索,真心好用(google用不了,退而求其次)。
就这样,结束。