什么网站可以做装修效果图,济南建站公司模板,关键词歌曲歌词,百度下载app安装背景#xff1a;
项目已通过vue-cli4框架开发并运行在nginx服务器上#xff08;使用了nginx的反向代理#xff09;#xff0c;现需要将该项目转成桌面端应用程序#xff0c;选择electron来实现。
设想2种解决方案#xff1a;
1、使用electron-quick-start的loadURL方法…背景
项目已通过vue-cli4框架开发并运行在nginx服务器上使用了nginx的反向代理现需要将该项目转成桌面端应用程序选择electron来实现。
设想2种解决方案
1、使用electron-quick-start的loadURL方法读取服务的线上url需要做一个用户URL输入界面便于部署。vue服务的版本迭代部署都和该electron无关
2、vue-cli项目引入electron并取代nginx服务器的功用 electron简介 Electron 使用 web 页面作为它的 GUI所以你能把它看作成一个被 JavaScript 控制的精简版的 Chromium 浏览器。 Electron大家应该不陌生了它提供了一种解决方案让我们能够利用Node.js 和 前端三宝 HTML JS CSS 来实现客户端软件。咋一听感觉像NW.js。其实NW.jsnodewebsocket可以算是Electron的前身了都是出自同个作者之手。关于Electron和NW.js的区别官网上是这么说的。简单讲就是Electron优化了NW.js中的一些不足。 秉着与时俱进的态度我们当然要使用Electron。有了Electron作为容器我们小前端就可以用HTMLJSCSS来开发客户端了。就像开发前端页面一样柔顺。Electron的使用比较简单提供的API也比较清晰。核心概念就是Main Process 和 Render Process。顾名思义Main Process是主进程用于运行Electron的基本操作如创建窗口创建菜单等。Render Process是渲染进程我们需要在渲染进程中创建软件界面每个渲染进程对应的是一个窗口主进程开启了多个窗口就会有多个渲染进程。
通俗解释electron使用nodejs将web应用套了一层壳使之变成了桌面应用。electron官网 electron-quick-start快速启动项目
下载 electron-quick-start demo 或使用git clone后启动
git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
cnpm install //这里我用的是cnpm,npm太慢了
npm start
启动成功效果 启动流程关注main.js、package.json、index.html这几个文件。从 package.json 文件看起我们运行 npm start 命令 其实是 运行了 electron . 命令该命令会从当前目录文件中寻找 package.json 文件找到 package.json 文件 然后读取 package.json 文件 中的 main 值main值 指向 main.js文件然后运行 man.js 文件找到index.html文件在主进程创建应用窗口创建桌面应用实例。 注意
1、npm start命令中的 “chcp 65001”表示使用utf-8的编码格式解决console打印乱码的问题
2、main进程中“nodeIntegration”配置表示是否集成nodejs模块 如何打包成exe桌面应用程序
需求分析loadURL方法读取服务的线上url但需要做一个URL输入界面便于用户输入vue服务的地址因为loadURL方法不管vue服务是否成功都会跳转url无法访问会导致electron打包后的桌面一片空白所以尽量在loadURL跳转页面前加以判定 解决方案一
流程
1、打包前需要确认已安装electron和electron-packager、jquery依赖
cnpm install electron --save-dev
cnpm install electron-packager --save-dev //这个是打成exe文件的插件之后要用提前下载好
cnpm install jquery --save-dev
2、在package.json配置文件中修改启动和打包命令
{name: electron-quick-start,version: 1.0.0,description: A minimal Electron application,main: main.js,scripts: {start: chcp 65001 electron ., //utf8编码格式启动electron_exe:electron-packager . --platformwin32 --archx64 --overwrite , //覆盖打包electron_all:electron-packager ./ notes --all --overwrite //全平台打包},repository: {type: git,url: githttps://github.com/electron/electron-quick-start.git},keywords: [Electron,quick,start,tutorial,demo],author: GitHub,license: CC0-1.0,devDependencies: {electron: ^11.2.0,electron-packager: ^15.2.0,jquery: ^3.5.1},bugs: {url: https://github.com/electron/electron-quick-start/issues},homepage: https://github.com/electron/electron-quick-start#readme,dependencies: {jquery: ^3.5.1 }
}3、在mian.js主进程中创建窗口配置nodeIntegration允许使用nodejs功能。这里使用了ipcMain和ipcRender主进程和渲染进程通信见后文或官网
// Modules to control application life and create native browser window
var electron require(electron);
var { app, BrowserWindow, Menu, ipcMain, globalShortcut } require(electron)
var path require(path)
var { dialog } require(electron)var electronScreen electron.screen; //window.screen 是一个预设值的 DOM 属性, 所以这样写 var screen require(electron).screen 将不会工作function createWindow() {var mainWindow new BrowserWindow({ //创建窗口// frame:false, //无边框width: 1400,height: 800,// fullscreen: true, //默认全屏展示webPreferences: {nodeIntegration: true, //false则禁用Node.js的require模块化引入preload: path.join(__dirname, preload.js),enableRemoteModule: true, //远程模块}})mainWindow.loadFile(index.html) //窗口读取本地文件// 在开发环境和生产环境均可通过快捷键打开devToolsglobalShortcut.register(ctrlF12, function () {if(mainWindow.webContents.isDevToolsOpened()){mainWindow.webContents.closeDevTools()}else {mainWindow.webContents.openDevTools() // 打开F12调试页面}})//主进程监听渲染进程发过来的数据ipcMain.on(asynchronous-message, (event, arg) {try {// console.log(主进程收到有效数据-----, arg) // prints pingmainWindow.loadURL(arg)} catch (err) {console.error(err)mainWindow.loadFile(index.html)}})Menu.setApplicationMenu(null) // 关闭菜单栏.//快捷键全屏globalShortcut.register(ctrlf11, () {if(mainWindow.isFullScreen()){mainWindow.setFullScreen(false);}else {mainWindow.setFullScreen(true);}})}// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() {createWindow()app.on(activate, function () {// On macOS its 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) {mouseTimer null;createWindow()}})})// Quit when all windows are closed, except on macOS. There, its common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd Q.
app.on(window-all-closed, function () {if (process.platform ! darwin) app.quit()mouseTimer null;
})4、index.html中可能出现CSP的安全策略Content-Security-Policy这里可以注释掉了。
!DOCTYPE html
htmlheadmeta charsetUTF-8!-- 关闭内容安全策略 --!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --!-- meta http-equivContent-Security-Policy contentdefault-src self; script-src selfmeta http-equivX-Content-Security-Policy contentdefault-src self; script-src self --titleHello Boy!/titlestylebody {text-align: center;}.url-setting {height: 20%;min-height: 150px;font-size: 30px;}/style/headbodyh1Hello World!/h1hrdiv classurl-settinginput typeurl idvueUrl placeholder格式如http://127.0.0.1:8080button idlinkBtn进入系统/button/divscript//解决在electron-packager打包为exe时nodejs无法require加载jquery的问题window.$ window.jQuery require(./node_modules/jquery/dist/jquery.min.js);/scriptscript src./renderer.js/script
/body/html 5、在renderer.js渲染进程中使用nodejs的require引入jquery会在exe包运行时报错“$ not defined ”所以在index.html中重新定义$要注意jquery依赖的文件路径是否能在打包好的electron项目下找到
// This file is required by the index.html file and will be executed in the renderer process for that window.
// No Node.js APIs are available in this process because nodeIntegration is turned off.
// Use preload.js to selectively enable features needed in the rendering process.// ipcRenderer 用于和主进程通信
const ipcRenderer require(electron).ipcRenderer;
//const $ require(jquery); //尽管nodeIntegration设置允许继承nodejs后可以正常启动electron但打包成exe时会报错//使用 remote 模块可以调用主进程对象的方法
const remote require(electron).remote;
const dialog remote.dialog;
const app remote.app;//使用nodejs读取本地文件数据安装electron-store也可以存储数据但响应性能受较大影响//electron-store存储数据
// const Store require(electron-store);
// const store new Store();
// const currentUrl store.get(serveUrl);const fs require(fs)//jquery检查连接的url服务是否有效,适用所有浏览器
$(document).ready(function () {// 执行代码var filePath ./serveUrl.txtif(app.isPackaged){ //app.isPackaged在生产模式则为truefilePath ./resources/app/serveUrl.txt}fs.readFile(filePath, function (error, data) { //if (error) {console.log(读取文件失败了,error)} else {$(#vueUrl).val(data.toString());}})function NetPing(pingUrl) {$.ajax({type: GET,cache: false,url: pingUrl,data: ,success: function () {fs.writeFile(filePath, pingUrl,function (error) { //存储用户输入的路径if (error) {console.log(存储URL失败,error)}}) ipcRenderer.send(asynchronous-message, pingUrl); //异步将渲染进程的数据传给主进程},error: function () {dialog.showErrorBox(错误提示, 无效网址请重新输入!)$(#vueUrl).val();}});}//点击连接vue前端服务$(#linkBtn).click(function () {let urlVal $(#vueUrl).val();if(urlVal){NetPing(urlVal);}else {dialog.showErrorBox(错误提示, 网址不能为空请重新输入!)}})
});//接收主进程的信息
ipcRenderer.on(asynchronous-reply, function (event, arg) {// console.log(arg); // prints pong
});注意没有使用electron-store存储持久化数据而是使用nodejs读存到本地文件serveUrl.txt上。引用本地文件时可以用app.isPackaged判断是否是生产环境 6、启动.\electron-quick-start\electron-quick-start-win32-x64成功 electron方案优缺点
对比于CocoaQt等传统桌面客户端技术基于前端技术的实现成本较低C牛请忽略跨平台支持更好框架都帮你做好了且天然支持热更新。
由于Electron本身包含了chromium和Node.js的代码, 所以不考虑项目本身体积打包后的软件最小仍然有100M, 这也是Electron最为显著的缺点之一。所以基本体积是无法避免的我们只能尽量减小其他开发文件的大小避免将一些无关包文件也打包进去。为什么要强调这点呢因为基于Node.js开发的项目往往会有一个庞大的node_modules文件夹里面包含了一些开发和生产所用的包也即对应package.json中的dependencies和devDependencies。而devDependencies中的包是不需要打包到软件的。这里推荐使用 electron-packager, 能自动排除dev依赖包并支持自定义排除包文件夹。也可以打包出支持不同系统格式的软件。
对于NW.js 有的大多数缺点Electron也有其中一个通病就是性能问题主要是渲染性能方面。基于webkit引擎来渲染UI界面跟原生的系统UI还是有一定的差距。毕竟是基于DOM节点的渲染每次节点的重排都是一次大的开销。这点只能通过在前端框架中来优化比如利用Virtual DOM等相关技术。而视觉上的缺点则可以通过CSS做到竟可能接近原生控件。 electron主进程和渲染进程间通信
Electron提供了IPC用于进程间通信。分别是ipcMain和ipcRender。该通信机制允许ipcRender向ipcMain发送信号请求并通过ipcMain返回数据。反回来ipcMain无法向特定的ipcRender发起请求。而且通信间传递的消息会被格式化为JSON字符串所以并不支持在两个进程间传递句柄方法等也就是不支持上下文传递。假如要实现在渲染进程中点击一个按钮则关闭客户端窗口可以通过ipcRender发送一个信号给ipcMain, ipcMain接收到该信号后调用Electron的API关闭窗口。对于类似这种比较简单的指令操作运用IPC实现就可以了但是如果操作比较复杂并且需要传递复杂数据类型则用IPC就行不通了。Electron提供了另一个API remote用于在Render Process中直接操作主进程的方法。这样就不需要移交Main Process处理直接在前端页面中调用Electron的API。
// In main process.
const ipcMain require(electron).ipcMain;
ipcMain.on(asynchronous-message, function(event, arg) {console.log(arg); // prints pingevent.sender.send(asynchronous-reply, pong);
});ipcMain.on(synchronous-message, function(event, arg) {console.log(arg); // prints pingevent.returnValue pong;
});
// In renderer process (web page).
const ipcRenderer require(electron).ipcRenderer;
console.log(ipcRenderer.sendSync(synchronous-message, ping)); // prints pongipcRenderer.on(asynchronous-reply, function(event, arg) {console.log(arg); // prints pong
});
ipcRenderer.send(asynchronous-message, ping); 解决方案二见下文