electron 起步

为什么要学 Electron,因为公司需要调试 electron 的应用。

Electron 是 nodechromium 的结合体,可以使用 JavaScript,HTML 和 CSS 等 Web 技术创建桌面应用程序,支持 Mac、Window 和 Linux 三个平台。

electron 的成功案例有许多,比如大名鼎鼎的 vscode

hello-world

官网有个快速启动的应用程序,我们将其下载到本地运行看一下。

# Clone this repository
git clone https://github.com/electron/electron-quick-start
# Go into the repository
cd electron-quick-start
# Install dependencies
npm install
# Run the app
npm start

:运行 npm i 时卡在> node install.js,许久后报错如下

$ npm i

> electron@20.1.0 postinstall electron\electron-quick-start\node_modules\electron
> node install.js RequestError: read ECONNRESET
at ClientRequest.<anonymous> (electron\electron-quick-start\node_modules\got\source\request-as-event-emitter.js:178:14)
at Object.onceWrapper (events.js:422:26)
at ClientRequest.emit (events.js:327:22)
at ClientRequest.origin.emit (electron\electron-quick-start\node_modules\@szmarczak\http-timer\source\index.js:37:11)
at TLSSocket.socketErrorListener (_http_client.js:432:9)
at TLSSocket.emit (events.js:315:20)
at emitErrorNT (internal/streams/destroy.js:84:8)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! electron@20.1.0 postinstall: `node install.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the electron@20.1.0 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

网上搜索 postinstall: node install.js 的解决办法是将 electron 下载地址指向 taobao 镜像:

// 将electron下载地址指向taobao镜像
$ npm config set electron_mirror "https://npm.taobao.org/mirrors/electron/"

新建项目 electron-demo 并参考 electron-quick-start

// 新建文件夹
$ mkdir electron-demo
// 进入项目
$ cd electron-demo
// 初始化项目
$ npm init -y
// 安装依赖包
$ npm i -D electron

新建 electron 入口文件 index.js

// electorn-demo/index.js
const { app, BrowserWindow } = require('electron')
const path = require('path') function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
})
// 加载html页面
mainWindow.loadFile('index.html')
} app.whenReady().then(() => {
createWindow()
})

新建一个 html 页面(例如 index.html):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron 网页</title>
</head>
<body>
hello world
</body>
</html>

在 package.json 中增加启动 electron 的命令:

{
"name": "electron-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 会运行 main 字段指向的 indx.js 文件
+ "start": "electron ."
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^20.1.1"
}
}

启动 electron 应用:

$ npm run start

Tip:windows 下通过 ctrl+shift+i 可以打开调试界面。或使用 mainWindow.webContents.openDevTools()也可以打开。

    // 加载html页面
mainWindow.loadFile('index.html')
// 默认打开调试工具
+ mainWindow.webContents.openDevTools()

热加载

现在非常不利于调试:修改 index.jsindex.html 需要新运行 npm run start 才能看到效果。

可以 electron-reloader 来解决这个问题。只要已修改代码,无需重启就能看到效果。

首先安装依赖包,然后修改 electron 入口文件即可:

$ npm i -D electron-reloader
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN electron-demo@1.0.0 No description
npm WARN electron-demo@1.0.0 No repository field. + electron-reloader@1.2.3
added 30 packages from 19 contributors and audited 109 packages in 26.217s 20 packages are looking for funding
run `npm fund` for details found 1 moderate severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details

electron 入口文件增加如下代码:

$ git diff index.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
// 参考 npmjs 包
+try {
+ require('electron-reloader')(module);
+} catch {}
+

重启服务后,再次修改 index.jsindex.html 等文件,只要保存就会自动看到效果。

主进程和渲染进程

官方api中有Main Process 模块Renderer Process 模块,比如我们在 hello-world 示例中使用的 BrowserWindow 标记了主进程,什么意思?

  • 主进程,通常是指 main.js 文件,是每个 Electron 应用的入口文件。控制着整个应用的生命周期,从打开到关闭。主进程负责创建 APP 的每一个渲染进程。一个 electron 应用有且只有一个主线程。
  • 渲染进程是应用中的浏览器窗口。 与主进程不同,渲染进程可能同时存在多个
  • 如果一个api同时属于两个进程,这里会归纳到 Main Process 模块
  • 如果在渲染进程中需要使用主进程的 api,需要通过 remote 的方式(下面会用到)。

菜单

通过 Menu.setApplicationMenu 新增菜单。代码如下:

// index.js
require('./menu.js')
// menu.js
const { BrowserWindow, Menu } = require('electron')
const template = [ {
id: '1', label: 'one',
submenu: [
{
label: '新开窗口',
click: () => {
const ArticlePage = new BrowserWindow({
width: 500,
height: 500,
})
ArticlePage.loadFile('article.html')
}
},
]
},
{ id: '2', label: 'two' },
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

效果如下图所示:

:新增窗口的菜单和主窗口的菜单相同。

自定义菜单

比如酷狗音乐,导航是比较好看。做法是隐藏原生菜单,用自己的 html 代替。

下面我们将原生菜单功能改为自定义菜单。

首先通过 frame 将应用的边框去除,原始菜单也不再可见:

const mainWindow = new BrowserWindow({
// frame boolean (可选) - 设置为 false 时可以创建一个无边框窗口 默认值为 true。
// 去除边框,菜单也不可见了
+ frame: false,
width: 1500,
height: 500,
})

Tip: frame boolean (可选) - 设置为 false 时可以创建一个无边框窗口 默认值为 true

接着在 html 页面实现自己的菜单。例如:

<p class="nav">
<span class="j-new">新建窗口</span>
<span>菜单2</span>
</p>

原始的导航是可以通过鼠标拖动。

我们可以使用 -webkit-app-region 来增加可拖拽效果:

<style>
.nav{-webkit-app-region: drag;}
.nav span{
-webkit-app-region: no-drag;
background-color:pink;
cursor: pointer;
}
</style>

:需要给菜单关闭拖拽效果,否则 cursor: pointer 会失效,点击也没反应,无法继续进行。

接下来给菜单添加事件,点击时打开新窗口。

这里得使用 BrowserWindow,则需要使用 require

直接使用 require 会报错 require is not defined。需要在主进程中开启:

const mainWindow = new BrowserWindow({
webPreferences: {
// 否则报错:require is not defined
+ nodeIntegration: true,
// 在新版本的electron中由于安全性的原因还需要设置 contextIsolation: false
+ contextIsolation: false,
},
})

接下来就得在引入 BrowserWindow,相当于在渲染进程中使用主进程的 api,需要使用 remote。如果这么用则会报错 const BrowserWindow = require("electron").remote.BrowserWindow,网友说:electron12 中已经废弃了remote 模块,如果需要则需自己安装 @electron/remote。

进入 npmjs 中搜索 @electron/remote,用于连接主进程到渲染进程的 js 对象:

// @electron/remote是Electron 模块,连接主进程到渲染进程的 js 对象

@electron/remote is an Electron module that bridges JavaScript objects from the main process to the renderer process. This lets you access main-process-only objects as if they were available in the renderer process.

// @electron/remote是electron内置远程模块的替代品,该模块已被弃用,最终将被删除。

@electron/remote is a replacement for the built-in remote module in Electron, which is deprecated and will eventually be removed.

用法如下:

// 安装依赖
$ npm install --save @electron/remote // 在主进程中进行初始化
require('@electron/remote/main').initialize()
require("@electron/remote/main").enable(mainWindow.webContents); // 渲染进程
const { BrowserWindow } = require('@electron/remote')

核心页面的完整代码如下:

  • 主进程页面:
// index.js 入口文件(主进程)

const { app, BrowserWindow} = require('electron')
// 在主进程中进行初始化,然后才能从渲染器中使用
require('@electron/remote/main').initialize() // 热加载
try {
require('electron-reloader')(module);
} catch { } function createWindow() {
const mainWindow = new BrowserWindow({ // 去除边框,菜单也不可见了
frame: false,
width: 1500,
height: 500,
webPreferences: {
// 否则报错:require is not defined
nodeIntegration: true,
// 在新版本的electron中由于安全性的原因还需要设置 contextIsolation: false
contextIsolation: false,
// 不需要 enableremoteModule,remote 也生效
// enableremoteModule: true
},
})
// 在electron >= 14.0.0中,您必须使用新的enableAPI 分别为每个所需的远程模块启用WebContents
// 笔者:"electron": "^20.1.1"
require("@electron/remote/main").enable(mainWindow.webContents); // 加载html页面
mainWindow.loadFile('index.html')
} app.whenReady().then(() => {
createWindow()
}) // 加载菜单
require('./menu.js')
  • 渲染进程页面
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron 网页</title>
<style>
.nav{-webkit-app-region: drag;}
.nav span{-webkit-app-region: no-drag;background-color:pink;cursor: pointer;}
</style>
</head>
<body>
<p class="nav">
<span class="j-new">新建窗口</span>
<span><a href='www.baidu.com'>百度</a></span>
</p> hello world2
<script src="index-js.js"></script>
</body>
</html>
// index-js.js 渲染进程

// 渲染窗口使用 require 浏览器报错:Uncaught ReferenceError: require is not defined
const { BrowserWindow } = require('@electron/remote') const elem = document.querySelector('.j-new')
elem.onclick = function(){
const ArticlePage = new BrowserWindow({
width: 500,
height: 500,
})
ArticlePage.loadFile('article.html')
}

打开浏览器

现在需要点击自定义菜单中的百度,然后打开浏览器并跳转到百度。

这里主要用到 shell,它属于主进程也属于渲染进程,所以这里无需使用 remote 方式引入。首先在 index.html 中增加 a 标签,然后在 js 中注册点击事件,最后调用 shell.openExternal 即可。请看代码:

<p class="nav">
<span class="j-new">新建窗口</span>
<span><a href='https://www.baidu.com'>百度</a></span>
</p>
// index-js.js
const { shell} = require('electron')
// 渲染窗口使用 require 浏览器报错:Uncaught ReferenceError: require is not defined
const { BrowserWindow } = require('@electron/remote') ...
const aElem = document.querySelectorAll('a'); [...aElem].forEach(item => item.onclick=(e)=>{
// 防止主进程打开页面
e.preventDefault()
const url = e.target.getAttribute('href');
shell.openExternal(url)
})

点击百度,会打开本地默认浏览器。

Tip:如果不要 http 直接写成 www.baidu.com,笔者测试失败。

文件读取和保存

先看要实现的效果:

点击读取,选择文件后,文件内容会显示到 textarea 中,对 textarea 进行修改文案,点击保存,输入要保存的文件名即可保存。

这里需要使用主进程的 dialog api。由于 dialog 属于主进程,要在渲染进程中使用,则需要使用 remote。

dialog - 显示用于打开和保存文件、警报等的本机系统对话框。这里用到两个 api 分别用于打开读取文件和保存文件的系统窗口:

  • dialog.showOpenDialogSync,打开读取文件的系统窗口,可以定义标题、确定按钮的文本、指定可显示文件的数组类型等等,点击保存,返回用户选择的文件路径。接下来就得用 node 去根据这个路径读取文件内容
  • dialog.showSaveDialogSync,与读文件类似,这里是保存,返回要保存的文件路径

Tip:真正读取文件和保存文件还是需要使用 node 的 fs 模块。有关 node 的读写文件可以参考这里

核心代码如下:

// index-js.js
const fs = require('fs')
const { BrowserWindow, dialog } = require('@electron/remote')
... // 文件操作
const readElem = document.querySelector('.j-readFile')
const textarea = document.querySelector('textarea')
const writeElem = document.querySelector('.j-writeFile')
// 读文件
readElem.onclick = function () {
// 返回 string[] | undefined, 用户选择的文件路径,如果对话框被取消了 ,则返回undefined。
const paths = dialog.showOpenDialogSync({ title: '选择文件', buttonLabel: '自定义确定' })
console.log('paths', paths)
fs.readFile(paths[0], (err, data) => {
if (err) throw err;
textarea.value = data.toString()
console.log(data.toString());
});
} // 写文件
writeElem.onclick = function () {
// 返回 string | undefined, 用户选择的文件路径,如果对话框被取消了 ,则返回undefined。
const path = dialog.showSaveDialogSync({ title: '保存文件', buttonLabel: '自定义确定' })
console.log('path', path)
// 读取要保存的内容
const data = textarea.value
fs.writeFile(path, data, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
}

注册快捷键

比如 vscode 有快捷键,这里我们也给加上。比如按 ctrl+m 时,最大化或取消最大化窗口。

这里需要使用 globalShortcut(主进程 ):在应用程序没有键盘焦点时,监听键盘事件。

用法很简单,直接注册即可。请看代码:

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

app.whenReady().then(() => {
const mainWindow = createWindow()
// 注册快捷键
globalShortcut.register('CommandOrControl+M', () => {
// 主进程会在 node 中输出,而非浏览器
console.log('CommandOrControl+M is pressed')
// 如果是不是最大,就最大化,否则取消最大化
!mainWindow.isMaximized() ? mainWindow.maximize() : mainWindow.unmaximize()
})
})

渲染进程中注册快捷键也类似,不过需要通过 remote 的方式引入。就像这样:

const { BrowserWindow, dialog, globalShortcut } = require('@electron/remote')

// 渲染进程中注册快捷键
globalShortcut.register('CommandOrControl+i', () => {
// 主进程会在 node 中输出,而非浏览器
console.log('CommandOrControl+i is pressed')
})

主线程和渲染进程通信

需求:在渲染进程中点击一个按钮,来触发主线程的放大或取消放大功能。

需要使用以下两个 api:

  • ipcMain 主进程 - 从主进程到渲染进程的异步通信。
  • ipcRenderer 渲染进程 - 从渲染器进程到主进程的异步通信。

Tip:在 Electron 中,进程使用 ipcMain 和 ipcRenderer 模块,通过开发人员定义的“通道”传递消息来进行通信。 这些通道是 任意 (您可以随意命名它们)和 双向 (您可以在两个模块中使用相同的通道名称)的。

首先在主进程注册事件:

ipcMain.on('max-unmax-event', (evt, ...args) => {
// max-unmax-event。args= [ 'pjl' ]
console.log('max-unmax-event。args=', args)
})

接着在 index.html 中增加最大化/取消最大化按钮:

<p class="nav">
<span class="j-new">新建窗口</span>
+ <span class="j-max">最大化/取消最大化</span>
</p>

最后在渲染进程中,点击按钮时通过 ipcRenderer 触发事件,并可传递参数。就像这样

// 最大化/取消最大化
const maxElem = document.querySelector('.j-max')
maxElem.onclick = function() {
ipcRenderer.send('max-unmax-event', 'pjl')
console.log('max')
}

打包

打包可以借助 electron-packager 来完成。

// 安装
$ npm install --save-dev electron-packager // 用法
npx electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...] // 就像这样
"build": "electron-packager ./ electron-demo --platform=win32 --arch=x64 ./outApp --overwrite --icon=./favicon.ico"

笔者环境是 node13.14,构建失败:

$ npm run build

> electron-demo@1.0.0 build electron\electron-demo
> electron-packager ./ electron-demo --platform=win32 --arch=x64 ./outApp --overwrite --icon=./favicon.ico CANNOT RUN WITH NODE 13.14.0
Electron Packager requires Node >= 14.17.5.
npm ERR! code ELIFECYCLE
...

react/vue 中使用 electron

用法很简单,首先准备好 react 或 vue 项目,笔者就以多次使用的 react(spug) 项目来进行。

安装 electron 包:

$ npm i -D electron

在 package.json 中增加运行命令,指定 electron 入口文件:

$ git diff package.json
"name": "spug_web",
+ "main": "electron-main.js",
"scripts": {
"test": "react-app-rewired test",
"eject": "react-scripts eject",
+ "electron": "electron ."
},
"devDependencies": {
+ "electron": "^20.1.2",

编写 electron 入口文件如下,其中 loadFile 要改为 loadURL

// electron-main.js
const { app, BrowserWindow } = require('electron')
const path = require('path') function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
})
// loadFile 改为 loadURL
mainWindow.loadURL('http://localhost:3000/')
} app.whenReady().then(() => {
createWindow()
})
// 启动 react 项目,在浏览器中能通过 http://localhost:3000/ 正常访问
$ npm run start
// 启动 electron
$ npm run electron

正常的话, electron 中就能看到 react 的项目。效果如下:

Tip:如果发布的话,首先通过 react 构建,例如输出 dir,然后将 loadURL 改为 loadFile('./dir/index.html')

完整代码

index.js

// index.js 入口文件(主进程)

const { app, BrowserWindow, globalShortcut, ipcMain} = require('electron')
// 在主进程中进行初始化,然后才能从渲染器中使用
require('@electron/remote/main').initialize() // 热加载
try {
require('electron-reloader')(module);
} catch { } function createWindow() {
const mainWindow = new BrowserWindow({ // frame boolean (可选) - 设置为 false 时可以创建一个无边框窗口 默认值为 true。
// 去除边框,菜单也不可见了
frame: false,
width: 1500,
height: 500,
webPreferences: {
// 否则报错:require is not defined
nodeIntegration: true,
// 在新版本的electron中由于安全性的原因还需要设置 contextIsolation: false
contextIsolation: false,
// 不需要 enableremoteModule,remote 也生效
// enableremoteModule: true
},
})
// 在electron >= 14.0.0中,您必须使用新的enableAPI 分别为每个所需的远程模块启用WebContents
// 笔者:"electron": "^20.1.1"
require("@electron/remote/main").enable(mainWindow.webContents); // 加载html页面
mainWindow.loadFile('index.html')
return mainWindow
} app.whenReady().then(() => {
const mainWindow = createWindow()
// 注册快捷键
globalShortcut.register('CommandOrControl+M', () => {
// 主进程会在 node 中输出,而非浏览器
console.log('CommandOrControl+M is pressed')
// 如果是不是最大,就最大化,否则取消最大化
!mainWindow.isMaximized() ? mainWindow.maximize() : mainWindow.unmaximize()
})
}) // 加载菜单
require('./menu.js') ipcMain.on('max-unmax-event', (evt, ...args) => {
console.log('max-unmax-event。args=', args)
})

index.html

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron 网页</title>
<style>
.nav{-webkit-app-region: drag;}
.nav span{-webkit-app-region: no-drag;background-color:pink;cursor: pointer;}
</style>
</head>
<body>
<p class="nav">
<span class="j-new">新建窗口</span>
<span><a href='https://www.baidu.com'>百度</a></span>
<span class="j-max">最大化/取消最大化</span>
</p> <p>hello world</p> <section>
<h3>文件操作</h3>
<textarea style="height:100px;width:100%;" placeholder="请先读取文件,修改后保存"></textarea>
<button class="j-readFile">读取文件</button>
<button class="j-writeFile">保存文件</button>
</section>
<script src="index-js.js"></script>
</body>
</html>

index-js.js

// index-js.js
const { shell, ipcRenderer } = require('electron')
const fs = require('fs')
// 渲染窗口使用 require 浏览器报错:Uncaught ReferenceError: require is not defined
const { BrowserWindow, dialog, globalShortcut } = require('@electron/remote') const elem = document.querySelector('.j-new')
elem.onclick = function () {
const ArticlePage = new BrowserWindow({
width: 500,
height: 500,
})
ArticlePage.loadFile('article.html')
} const aElem = document.querySelectorAll('a'); [...aElem].forEach(item => item.onclick = (e) => {
e.preventDefault()
const url = e.target.getAttribute('href');
console.log('href', url) shell.openExternal(url)
}) // 文件操作
const readElem = document.querySelector('.j-readFile')
const textarea = document.querySelector('textarea')
const writeElem = document.querySelector('.j-writeFile')
// 读文件
readElem.onclick = function () {
// 返回 string[] | undefined, 用户选择的文件路径,如果对话框被取消了 ,则返回undefined。
const paths = dialog.showOpenDialogSync({ title: '选择文件', buttonLabel: '自定义确定' })
console.log('paths', paths)
fs.readFile(paths[0], (err, data) => {
if (err) throw err;
textarea.value = data.toString()
console.log(data.toString());
});
} // 写文件
writeElem.onclick = function () {
// 返回 string | undefined, 用户选择的文件路径,如果对话框被取消了 ,则返回undefined。
const path = dialog.showSaveDialogSync({ title: '保存文件', buttonLabel: '自定义确定' })
console.log('path', path)
// 读取要保存的内容
const data = textarea.value
console.log('data', data)
fs.writeFile(path, data, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
} // 渲染进程中注册快捷键
globalShortcut.register('CommandOrControl+i', () => {
// 主进程会在 node 中输出,而非浏览器
console.log('CommandOrControl+i is pressed')
// mainWindow.webContents.openDevTools()
// // 如果是不是最大,就最大化,否则取消最大化
// !mainWindow.isMaximized() ? mainWindow.maximize() : mainWindow.unmaximize()
}) // 最大化/取消最大化
const maxElem = document.querySelector('.j-max')
maxElem.onclick = function() {
ipcRenderer.send('max-unmax-event', 'pjl')
console.log('max')
}

menu.js

// menu.js
const { BrowserWindow, Menu } = require('electron')
const template = [ {
id: '1', label: 'one',
submenu: [
{
label: '新开窗口',
click: () => {
const ArticlePage = new BrowserWindow({
width: 500,
height: 500,
})
ArticlePage.loadFile('article.html')
}
},
]
},
{ id: '2', label: 'two' },
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

package.json

{
"name": "electron-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron .",
"build": "electron-packager ./ electron-demo --platform=win32 --arch=x64 ./outApp --overwrite --icon=./favicon.ico"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^20.1.1",
"electron-packager": "^16.0.0",
"electron-reloader": "^1.2.3"
},
"dependencies": {
"@electron/remote": "^2.0.8"
}
}

electron 起步的更多相关文章

  1. 初探Electron

    Electron是什么? 官网是这么描述的:Build cross platform desktop apps with JavaScript, HTML, and CSS 翻译一下:使用JavaSc ...

  2. electron-vue:Vue.js 开发 Electron 桌面应用

    相信很多同学都知道 Electron 可以帮助开发人员使用前端技术开发桌面客户端应用,今天介绍的 electron-vue 框架是一套基于 Vue.js 开发 Electron 桌面应用的脚手架,该项 ...

  3. 初探Electron,从入门到实践

    本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.   在开始之前,我想您一定会有这样的困惑:标题里的Electron ...

  4. 快速了解Electron:新一代基于Web的跨平台桌面技术

    本文引用了作者“ ConardLi”的<用JS开发跨平台桌面应用,从原理到实践>一文部分内容,原文链接:segmentfault.com/a/1190000019426512,感谢原作者的 ...

  5. 什么是electron

    Electron 是什么 定义 Electron是一个能让你使用传统前端技术(Nodejs, Javascript, HTML, CSS)开发一个跨平台桌面应用的框架.这里所说的桌面应用指的是在Win ...

  6. electron 应用开发优秀实践

    vivo 互联网前端团队-Yang Kun 一.背景 在团队中,我们因业务发展,需要用到桌面端技术,如离线可用.调用桌面系统能力.什么是桌面端开发?一句话概括就是:以 Windows .macOS 和 ...

  7. Electron使用与学习--(页面间的通信)

    目录结构: index.js是主进程js. const electron = require('electron') const app = electron.app const BrowserWin ...

  8. Electron使用与学习--(基本使用与菜单操作)

    对于electron是个新手,下面纯属个人理解.如有错误,欢迎指出.   一.安装 如果你本地按照github上的 # Install the `electron` command globally ...

  9. Electron 不完全快速手册

    Electron能干嘛 Vscode 基于Electron开发的,他是用来开发桌面软件的,可以轻易的跨平台 他的前身是atomshell,图标很丑,不用在意,一点也不像vscode也不用在意.   L ...

随机推荐

  1. sql-DQL-单表查询

    单表查询 select [distint]* 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 order by 排序 limit 分页限定 ...

  2. svn提交报错Unexpected HTTP status 413 'Request Entity Too Large' on

    问题原因:nginx的client_max_body_size设置过小,默认 1M,如果请求的正文数据大于client_max_body_size,HTTP协议会报错 413 Request Enti ...

  3. 开发人员要学的Docker从入门到日常命令使用(通俗易懂),专业运维人员请勿点!

    一.介绍Docker  1.引言 问题1:开发人员告诉测试说自己的项目已经做好了,给你一个发布包,你去测试吧. ## 测试人员,为什么我运行会报错? ## 开发人员说,我本地运行没有问题呀!   解答 ...

  4. Zabbix 5.0:通过LLD方式自动化监控阿里云RDS

    Blog:博客园 个人 之前做了RDS监控,由于 RDS 实例梳理增多,手动添加的方式已经不够效率,故改为LLD(Low-level discovery)方式做监控. 什么是LLD LLD(Low-l ...

  5. MicTR01 Tester 开发套件(振弦采集读数仪)使用说明

    MicTR01 是系列振弦模块 VM5/6/7和电子标签读写模块 TR01 开发测试.开发套件.使用 STC8 位 51 单片机为核心部件,演示上述各个型号模块的基本用法,包括了模块使用时的硬件连接和 ...

  6. ABAP BAPI 复制标准项目模板实现项目立项

    一.复制标准项目模板实现项目立项 因为CJ20N录屏存在困难,所以想通过BDC实现复制项目模板创建项目立项行不通,因此需要通过BAPI解决. 因为项目立项包含:项目定义.WBS.网络.作业,因此需要分 ...

  7. super详解(继承)

    //在Java中,所有的类,都默认直接或者间接继承objec类// Person 人 :父类public class Person /*extends object*/ { public Person ...

  8. 透过Redis源码探究Hash表的实现

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/667 本文使用的Redis 5.0源码 概述 我们在学习 Redis ...

  9. ROS机械臂 Movelt 学习笔记3 | kinect360相机(v1)相关配置

    目标是做一个机械臂视觉抓取的demo,在基地里翻箱倒柜,没有找到学长所说的 d435,倒是找到了一个老古董 kinect 360. 前几天就已经在旧电脑上配置好了,现在记录在新电脑上的配置过程. 1. ...

  10. java------JRE和JDK

    JDK(Java Development kit):Java开发工具包 包括 JVM(Java Virtual Machine):java虚拟机,真正运行java程序的地方(Java语言在运行时并不是 ...