IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 大前端 - 泛客户端 - Electron -> 正文阅读

[JavaScript知识库]大前端 - 泛客户端 - Electron

Electron 是一个跨平台的、基于 Web 前端技术的桌面 GUI 应用程序开发框架。

使用 Web 前端技术来开发一个桌面 GUI 程序是一件多么炫酷的事情,你可以使用 HTML、CSS 来绘制界面和控制布局,使用 JavaScript 来控制用户行为和业务逻辑,使用 Node.js 来通信、处理音频视频等,几乎所有的 Web 前端技术和框架(jQuery、Vue、React、Angular 等)都可以应用到桌面 GUI 开发中。

至此,JavaScript 这门神奇的语言除了能开发 Web 前端、Web 后台(基于 Node.js)、手机 APP(基于 React),也能开发桌面 GUI 程序了。

想开发一个桌面 GUI 应用软件,希望其能同时在 Windows、Linux 和 Mac 平台上运行,可选的技术框架并不多。

基于 Electron 的应用

  1. 软件开发领域
    在软件开发领域,最为开发人员所熟知的无过于 Visual Studio Code 了。Visual Studio Code 依靠丰富的功能、极速的响应、极佳的用户体验赢得了广大开发人员的青睐。作为一个新兴的 IDE 工具,其在最近一期的 IDE 排行榜单中排名第七,用户量持续迅猛增长。

另外,MongoDB 桌面版管理工具 Compass 也是基于 Electron 开发的。

  1. 社交通信领域
    社交通信领域风靡全球的 Skype 桌面版和 WhatsApp 桌面版、高效办公领域的 Slack 和飞书、视听领域的 Nuclear(一款很有趣的音乐播放器)和 WebTorrent Desktop(以P2P协议播放音视频的应用)、金融交易领域的 OpenFin、早期的以太坊客户端 Mist 和 Brave 浏览器(由前 Mozilla CEO 和 JavaScript 之父 Brendan Eich 创建)等,都是基于 Electron 打造的。

  2. Web 界面测试领域
    Electron 还被用于 Web 界面测试。自 PhantomJS 宣布停止更新后,Electron 成了有力的替代者。

测试工程师可以通过编写自动化测试脚本,轻松地控制 Electron 访问网页元素、提交用户输入、验证界面表现、跟踪执行效率等。另外,知名的 HTTP 网络测试工具 Postman 也是基于 Electron 开发的。

  1. Electron 是极客喜爱的工具
    由于 Electron 有自定义代理、截获网络请求、注入脚本到目标网站的能力,它也成了众多极客的趁手工具,比如有开发者开发过一个音乐聚合软件,把 QQ 音乐、网易云音乐、虾米音乐聚合在一个软件里播放。

Electron 的生态

electron-builder 是一个 Electron 的构建工具,它提供了自动下载、自动构建、自动打包、自动升级等能力,是 Electron 生态中的基础支持工具,大部分流行的 Electron 应用都使用它进行构建和分发。

在 Electron 应用内存取本地数据,可以使用 Cookie、LocalStorage 或 IndexedDB 这些传统的前端技术,也可以选择 Electron 生态内的一些方案,例如:
rxdb 是一个可以在 Electron 应用内使用的实时 NoSQL 数据库;
如果希望使用传统的数据库,也可以在 Electron 内使用 SQLite 数据库。

Vue CLI Plugin Electron Builder 和 electron-vue 是两个非常不错的工具,开发者可以基于它们轻松地在 Electron 应用内使用 Vue 及其组件(包括 HMR 热更新技术)。虽然后者拥有更多的 GitHub star,更受欢迎,但我推荐使用前者。前者基于 Vue CLI Plugin 开发,更新频繁,而后者已经有近一年时间没更新过了。

electron-react-boilerplate 是一个项目模板,它把 Electron、React、Redux、React Router、Webpack 和 React Hot Loader 组合在一起。开发者基于此模板可以快速构建 React 技术体系的 Electron 应用。

angular-electron 也是一个项目模板,开发者可以基于它快速构建基于 Angular 和 Electron 的应用。

如果不希望使用上述前端框架,仅希望使用 webpack 与传统 Web 前端开发技术开发 Electron 应用,可以考虑使用 electron-webpack 组件完成工作。

另外,awesome-electron 项目记录了大量与 Electron 有关的有趣的项目和组件。

Electron 的优势

Electron 基于 Web 技术开发桌面应用。Web 技术是现如今软件开发领域应用最广泛的技术之一,入门门槛非常低,周边生态繁荣而且历史悠久。

  1. Electron 开发效率高
    相较于基于 C++ 库开发桌面软件来说,基于 Electron 开发更容易上手且开发效率更高。由于 JavaScript 语言是一门解释执行的语言,所以 C++ 语言固有的各种问题都不再是问题,比如:
    C++ 没有垃圾回收机制,开发人员要小心翼翼地控制内存,以免造成内存泄漏;
    C++ 语言特性繁多且复杂,学习难度曲线陡峭,需要针对不同平台进行编译,应用分发困难。

使用 Electron 开发桌面应用就不用担心这些问题。

  1. Electron 执行效率高
    在执行效率上,如果前端代码写得足够优秀,Electron 应用完全可以做出与 C++ 应用相媲美的用户体验,Visual Studio Code 就是先例。

另外,Node.js 本身也可以很方便地调用 C++ 扩展,Electron 应用内又包含 Node.js 环境,对于一些音视频编解码或图形图像处理需求,可以使用 Node.js 的 C++ 扩展来完成。

  1. Electron 立足于 JavaScript 生态
    随着 Web 应用大行其道,Web 前端开发领域的技术生态足够繁荣。Electron 可以使用几乎所有的 Web 前端生态领域及 Node.js 生态领域的组件和技术方案。截至本文发布时,发布到 npmjs.com 平台上的模块已经超过 90 万个,覆盖领域广,优秀模块繁多且使用非常简单方便。

  2. 无需考虑兼容性问题
    在完成 Web 前端开发工作时,开发者需要考虑很多浏览器兼容的问题,比如:用户是否使用了低版本的 IE 浏览器,是否可以在样式表内使用 Flexbox(弹性盒模型)等。这些问题最终会导致前端开发者束手束脚,写出一些丑陋的兼容代码以保证自己的应用能在所有终端表现正常。

但由于 Electron 内置了 Chromium 浏览器,该浏览器对标准支持非常好,甚至支持一些尚未通过的标准,所以基于 Electron 开发应用不会遇到兼容问题。开发者的自由度得到了最大化保护,你可以在 Electron 中使用几乎所有 HTML5、CSS3、ES6 标准中定义的 API。

  1. Electron 可以使用操作系统接口
    另外,Web 前端受限访问的文件系统、系统托盘、系统通知等,在 Electron 技术体系下均有 API 供开发者自由使用。

Electron 的不足

基于 Electron 开发桌面 GUI 应用并不是完美的方案,它也有它的不足,综合来说有以下几点。

  1. 打包后的应用体积巨大
    一个功能不算多的桌面应用,通过 electron-builder 压缩打包后至少也要 40MB。如果开发者不做额外的 Hack 工作的话,用户每次升级应用程序,还要再下载一次同样体积的安装包,这对于应用分发来说是一个不小的负担。但随着网络环境越来越好,用户磁盘的容积越来越大,此问题给用户带来的损失会慢慢被削弱。

  2. 开发复杂度较大,进阶曲线较陡
    跨进程通信是基于 Electron 开发应用必须要了解的知识点,虽然 Electron 为渲染进程提供了 remote 模块来方便开发人员实现跨进程通信,但这也带来了很多问题,比如某个回调函数为什么没起作用、主进程为什么报了一连串的错误等,这往往给已经入门但需要进阶的开发者带来困惑。

  3. 版本发布过快
    为了跟上 Chromium 的版本发布节奏,Electron 也有非常频繁的版本发布机制,每次 Chromium 改动,都可能导致 Electron 出现很多新问题,甚至稳定版本都有很多未解决的问题。幸好 Electron 的关键核心功能一直以来都是稳定的。

  4. 安全性问题
    Electron 把一些有安全隐患的模块和 API 都设置为默认不可用的状态,但这些模块和 API 都是非常常用的,因此有时开发者不得不打开这些开关。但是,一旦处理不当,就可能导致开发的应用存在安全隐患,给开发者乃至终端用户带来伤害。

安全问题有很多值得关注的技术细节,以至于 Electron 官方文档中专门开辟出来一个章节号召程序员重视安全问题。但我认为,很多时候安全和自由是相悖的,在不损失自由的前提下提升安全指标的工作是值得肯定的,如果哪天 Electron 以安全为由停用脚本注入的技术,相信很多开发者都会反对。

  1. 资源消耗较大
    Electron 底层基于的 Chromium 浏览器一直以来都因资源占用较多被人诟病,目前来看这个问题还没有很好的解决办法,只能依赖 Chromium 团队的优化工作。

Electron工作流程

  • 主进程(main):可以看作是package.json中main属性对应的文件
    一个文件只能有一个主进程。
    只有主进程可以进程gui的api操作。

  • 渲染进程(gui):windows中展示的界面通过渲染进程表现。
    可以进行所有的dom操作。
    一个应用可以有多个渲染进程。

当启动一个程序的时候,首先会启动一个主进程,一般就是我们要去执行的main.js / index.js, 当前主进程启动完成之后,就会创建一个/ 多个browers window来呈现界面,这个其实就是web页面。这个时候每个browers window都可以看成是一个进程,对于不同的进程来说,他们之间是相互独立的,各自运行在自己的沙箱环境之中,不通的窗口之间的的数据是可以通信的,他们之间的通信依赖于:ipc通信机制。
请添加图片描述

请添加图片描述

Electron环境搭建

快速创建应用:https://www.electronjs.org/

// 快速创建项目
git clone https://github.com/electron/electron-quick-start

// 进入这个仓库
cd electron-quick-start

// 安装依赖并运行
npm install && npm start

main.js文件解析:

// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')

// 1.创建一个窗口
// 2.让窗口加载了一个界面,这个界面就是web技术实现的,这个界面是运行在渲染进程中的。
function createWindow () {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

// 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 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()
  })
})

// Quit when all windows are closed, except on macOS. There, it's 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()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

  • 自己搭建Electron脚手架
  1. npm init -y
  2. npm i electron -g
    main.js
const { app, BrowserWindow } = require('electron')

// 当 app 启动之后执行窗口创建等操作
app.whenReady().then(() => {
  const mainWin = new BrowserWindow({
    width: 600,
    height: 400
  })

  // 在当前窗口中加载指定界面让它显示具体的内容
  mainWin.loadFile('index.html')

  mainWin.on('close', () => {
    console.log('close~~~~~~')
  })
})

app.on('window-all-closed', () => {
  console.log('all windows is closed')
  app.quit()
})

indexhtml

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的electron</title>
</head>

<body>
  <h2>自定义桌面应用</h2>
</body>

</html>

package.json

{
  "name": "02-elctron-start",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^11.2.1"
  }
}

启动:npm run start

Electron生命周期

请添加图片描述
main.js

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

// 创建窗口
function createWindow() {
  let mainWin = new BrowserWindow({
    width: 800,
    height: 400
  })

  mainWin.loadFile('index.html')

  mainWin.webContents.on('did-finish-load', () => {
    console.log('33333--->did-finish-load')
  })

  mainWin.webContents.on('dom-ready', () => {
    console.log('22222--->dom-ready')
  })

  mainWin.on('close', () => {
    console.log('88888--->this window is closed')
    mainWin = null
  })
}

app.on('ready', () => {
  console.log('11111----->ready')
  createWindow()
})

app.on('window-all-closed', () => {
  console.log('44444---->window-all-closed')
  app.quit()
})

app.on('before-quit', () => {
  console.log('5555->before-quit')
})

app.on('will-quit', () => {
  console.log('66666->will-quit')
})


app.on('quit', () => {
  console.log('777777-quitquit')
})

窗口尺寸

创建/控制窗口的尺寸。
main.js

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

// 将创建窗口独立成一个函数
function createWindow() {
  let mainWin = new BrowserWindow({
    x: 100,
    y: 100,  // 设置窗口显示的位置,相对于当前屏幕的左上角
    show: false,  // 默认情况下创建一个窗口对象之后就会显示,设置为false 就不会显示了
    width: 800,
    height: 400,
    maxHeight: 600,
    maxWidth: 1000,
    minHeight: 200,
    minWidth: 300,  // 可以通过 min max 来设置当前应用窗口的最大和最小尺寸
    resizable: false  // 是否允许缩放应用的窗口大小 
  })

  mainWin.loadFile('index.html')
  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })
  mainWin.on('close', () => {
    console.log('mainWin is closed')
    mainWin = null
  })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
  console.log('all window is closed')
  app.quit()
})

package.json

{
  "name": "04-app-window-size",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon --watch main.js --exec npm run build",
    "build": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^11.2.1"
  }
}

窗口标题及环境

main.js

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

// 将创建窗口独立成一个函数
function createWindow() {
  let mainWin = new BrowserWindow({
    show: true,
    width: 800,
    height: 600,
    frame: true,  // 用于自定义 menu ,设置为 false 可以将默认的菜单栏隐藏
    // transparent: true,
    autoHideMenuBar: true,
    icon: 'lg.ico',  // 设置一个图片路径,可以自定义当前应用的显示图标
    title: "electron",  // 自定义当前应用的显示标题
    
    // 允许渲染进程使用node语法(渲染进程集成node)
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })

  mainWin.loadFile('index.html')
  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })
  mainWin.on('close', () => {
    console.log('mainWin is closed')
    mainWin = null
  })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
  console.log('all window is closed')
  app.quit()
})

点击按钮打开新窗口:
index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
</head>

<body>
  <h2>窗口标题</h2>
  <button id="btn">点击打开新窗口</button>
  <script src="index.js"></script>
</body>

</html>

index.js

// 在渲染进程中使用:electron
const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {
  // 点击按钮打开一个新窗口
  const oBtn = document.getElementById('btn')
  oBtn.addEventListener('click', () => {
    // ?? 如何去创建窗口
    let indexMin = new remote.BrowserWindow({
      width: 200,
      height: 200
    })
    // 加载页面
    indexMin.loadFile('list.html')

    indexMin.on("close", () => {
      indexMin = null
    })
  })
})

list.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>新窗口</title>
</head>

<body>
  <h2>新窗口</h2>
</body>

</html>

自定义窗口

main.js

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

// 将创建窗口独立成一个函数
function createWindow() {
  let mainWin = new BrowserWindow({
    frame: false,
    width: 800,
    height: 400,
    webPreferences: {  // 用于控制窗口加载的网页是否集成 node.js 环境
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })
  mainWin.loadFile('index.html')
  mainWin.on('close', () => {
    console.log('mainWin is closed')
    mainWin = null
  })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
  console.log('all window is closed')
  app.quit()
})

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>创建窗口</title>
  <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .box {
      width: 100%;
      height: 400px;
      overflow: hidden;
      background-color: seashell;
    }

    .bar {
      height: 40px;
      box-shadow: 0 1 5px 0px #333;
      border-bottom: 1px solid #ccc;
    }

    .titleBar {
      width: 190px;
      float: left;
      height: 40px;
      margin-left: 10px;
    }

    .titleBar div {
      float: left;
      height: 40px;
    }

    .titleBar .logo {
      width: 20px;
      height: 20px;
      margin-top: 10px;
      background: url('./lg.ico') 0 0 no-repeat;
      background-size: cover;
    }

    .titleBar .title {
      margin-left: 10px;
      font: normal 14px/40px '微软雅黑'
    }

    .windowTool {
      float: right;
      width: 600px;
      height: 40px;
      position: relative;
    }

    .windowTool div {
      float: right;
      cursor: pointer;
      margin-right: 20px;
      font: normal 12px/40px '微软雅黑'
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="bar">
      <div class="titleBar">
        <div class="logo"></div>
        <div class="title">electron</div>
      </div>
      <div class="windowTool">
        <div class="close">
          <i class="fa fa-window-close-o" aria-hidden="true"></i>
        </div>
        <div class="maxsize">
          <i class="fa fa-window-maximize" aria-hidden="true"></i>
        </div>
        <div class="minisize">
          <i class="fa fa-minus"></i>
        </div>
      </div>
    </div>
    <div>主体内容</div>
  </div>
  <script src="index.js"></script>
</body>

</html>

index.js

const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {

  // 利用 remote 可以获取当前窗口对象
  let mainWin = remote.getCurrentWindow()
   console.log('mainWin', mainWin)
  
  // 获取元素添加点击操作的监听
  let aBtn = document.getElementsByClassName('windowTool')[0].getElementsByTagName('div')

  aBtn[0].addEventListener('click', () => {
    // 当前事件发生后说明需要关闭窗口
    mainWin.close()
  })


  aBtn[1].addEventListener('click', () => {
    // 这里需要执行的最大化操作
    console.log(mainWin.isMaximized())
    if (!mainWin.isMaximized()) {
      mainWin.maximize()  // 让当前窗口最大化
    } else {
      mainWin.restore()  // 回到原始的状态
    }
  })

  aBtn[2].addEventListener('click', () => {
    // 实现最小化
    if (!mainWin.isMinimized()) {
      mainWin.minimize()
    }
  })
})

阻止窗口关闭

main.js

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

// 将创建窗口独立成一个函数
function createWindow() {
  let mainWin = new BrowserWindow({
    frame: false,
    width: 800,
    height: 400,
    webPreferences: {  // 用于控制窗口加载的网页是否集成 node.js 环境
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })
  mainWin.loadFile('index.html')
  mainWin.on('close', () => {
    console.log('mainWin is closed')
    mainWin = null
  })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
  console.log('all window is closed')
  app.quit()
})

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>创建窗口</title>
  <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .box {
      width: 100%;
      height: 400px;
      overflow: hidden;
      background-color: seashell;
    }

    .bar {
      height: 40px;
      box-shadow: 0 1 5px 0px #333;
      border-bottom: 1px solid #ccc;
    }

    .titleBar {
      width: 190px;
      float: left;
      height: 40px;
      margin-left: 10px;
    }

    .titleBar div {
      float: left;
      height: 40px;
    }

    .titleBar .logo {
      width: 20px;
      height: 20px;
      margin-top: 10px;
      background: url('./lg.ico') 0 0 no-repeat;
      background-size: cover;
    }

    .titleBar .title {
      margin-left: 10px;
      font: normal 14px/40px '微软雅黑'
    }

    .windowTool {
      float: right;
      width: 600px;
      height: 40px;
      position: relative;
    }

    .windowTool div {
      float: right;
      cursor: pointer;
      margin-right: 20px;
      font: normal 12px/40px '微软雅黑'
    }

    .isClose {
      top: 50%;
      left: 50%;
      width: 380px;
      height: 180px;
      padding: 10px;
      position: fixed;
      display: none;
      background: #f5f5f5;
      box-shadow: 0px 1px 5px 0px #ccc;
      transform: translate(-50%, -50%);
    }

    .isClose h3 {
      text-align: center;
      font: bold 14px/40px '微软雅黑';
    }

    .isClose p {
      font: normal 12px/40px '微软雅黑'
    }

    .close_btn {
      margin-top: 60px;
      margin-left: 220px;
    }

    .close_btn span {
      float: left;
      width: 60px;
      margin-left: 8px;
      text-align: center;
      border-radius: 4px;
      border: 1px solid #ccc;
      font: normal 12px/26px '微软雅黑';
    }

    .close_btn span:nth-child(1) {
      cursor: pointer;
      color: #fff;
      background-color: #7b8c7c;
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="bar">
      <div class="titleBar">
        <div class="logo"></div>
        <div class="title">electron</div>
      </div>
      <div class="windowTool">
        <div class="close">
          <i class="fa fa-window-close-o" aria-hidden="true"></i>
        </div>
        <div class="maxsize">
          <i class="fa fa-window-maximize" aria-hidden="true"></i>
        </div>
        <div class="minisize">
          <i class="fa fa-minus"></i>
        </div>
      </div>
    </div>
    <div id="abc">主体内容</div>

    <!-- 定义浮窗设置阻止窗口关闭样式 -->
    <div class="isClose">
      <h3>是否关闭当前应用?</h3>
      <p>系统可能不会保存您的所有更改</p>
      <p class="close_btn"><span></span><span></span></p>
    </div>
  </div>
  <script src="./index.js"></script>
</body>

</html>

index.js

const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {

  window.onbeforeunload = function () {
    let oBox = document.getElementsByClassName('isClose')[0]
    oBox.style.display = 'block'

    let yesBtn = oBox.getElementsByTagName('span')[0]
    let noBtn = oBox.getElementsByTagName('span')[1]

    yesBtn.addEventListener('click', () => {
      mainWin.destroy()
    })

    noBtn.addEventListener('click', () => {
      oBox.style.display = 'none'
    })

    return false
  }

  // 利用 remote 可以获取当前窗口对象
  let mainWin = remote.getCurrentWindow()

  // 获取元素添加点击操作的监听
  let aBtn = document.getElementsByClassName('windowTool')[0].getElementsByTagName('div')

  aBtn[0].addEventListener('click', () => {
    // 当前事件发生后说明需要关闭窗口
    mainWin.close()
  })

  aBtn[1].addEventListener('click', () => {
    // 这里需要执行的最大化操作
    console.log(mainWin.isMaximized())
    if (!mainWin.isMaximized()) {
      mainWin.maximize()  // 让当前窗口最大化
    } else {
      mainWin.restore()  // 回到原始的状态
    }
  })

  aBtn[2].addEventListener('click', () => {
    // 实现最小化
    if (!mainWin.isMinimized()) {
      mainWin.minimize()
    }
  })
})

父子及模态窗口

自定义菜单

main.js

const { app, BrowserWindow, Menu } = require('electron')
// 获取当前的操作系统:process.platform
console.log(process.platform)
const createWindow = function () {
  let mainWin = new BrowserWindow({
    title: '自定义菜单',
    show: false,
    width: 800,
    height: 400,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })

  // 定义自己需要的菜单项
  let menuTemp = [
    {
      label: '文件',
      submenu: [
        {
          label: '打开文件',
          click() {
            console.log('当前需要做的就是打开某一个具体的文件')
          }
        },
        {
          type: 'separator' // 菜单分隔符
        },
        {
          label: '关闭文件夹'
        },
        {
          label: '关于',
          role: 'about'
        }
      ]
    },
    { label: '编辑' }
  ]

  // 利用上述的模板然后生成一个菜单项
  let menu = Menu.buildFromTemplate(menuTemp)

  // 将上述的自定义菜单添加到应用里
  Menu.setApplicationMenu(menu)

  mainWin.loadFile('index.html')
  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })
  mainWin.on('close', () => {
    mainWin = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  app.quit()
})

菜单角色及类型

main.js

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

const createWindow = function () {
  let mainWin = new BrowserWindow({
    show: false,
    width: 800,
    height: 600,
    icon: './lg.ico',
    title: 'electron',
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })

  // 01 自定义菜单的内容
  let menuTemp = [
    {
      label: '角色',
      submenu: [
        { label: '复制', role: 'copy' },
        { label: '剪切', role: 'cut' },
        { label: '粘贴', role: 'paste' },
        { label: '最小化', role: 'minimize' },
      ]
    },
    {
      label: '类型',
      submenu: [
        { label: '选项1', type: 'checkbox' },
        { label: '选项2', type: 'checkbox' },
        { label: '选项3', type: 'checkbox' },
        { type: "separator" },
        { label: 'item1', type: "radio" },
        { label: 'item2', type: "radio" },
        { type: "separator" },
        { label: 'windows', type: 'submenu', role: 'windowMenu' }
      ]
    },
    {
      label: '其它',
      submenu: [
        {
          label: '打开',
          icon: './open.png', // 图标
          accelerator: 'ctrl + o', // 添加自定义快捷键
          click() { // 回调函数
            console.log('open操作执行了')
          }
        }
      ]
    }
  ]

  // 02 依据上述的数据创建一个 menu 
  let menu = Menu.buildFromTemplate(menuTemp)

  // 03 将上述的菜单添加至 app 身上
  Menu.setApplicationMenu(menu)

  mainWin.loadFile('index.html')

  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })

  mainWin.on('close', () => {
    mainWin = null
  })
}

app.on('ready', () => {
  createWindow()
})

app.on('window-all-closed', () => {
  app.quit()
})

动态创建菜单

main.js

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

const createWindow = function () {

  let mainWin = new BrowserWindow({
    show: false,
    width: 800,
    height: 400,
    title: 'electron',
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })
  mainWin.loadFile('index.html')

  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })

  mainWin.on('close', () => {
    mainWin = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  app.quit()
})

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
</head>

<body>
  <h2>自定义菜单</h2>

  <button id="addMenu">创建自定义菜单</button>
  <br>
  <br>
  <input type="text" placeholder="输入自定义菜单项内容" id="menuCon">
  <br>
  <br>
  <button id="addItem">添加菜单项</button>

  <script src="./index.js"></script>
</body>

</html>

index.js

const { remote } = require('electron')
const Menu = remote.Menu
const MenuItem = remote.MenuItem

window.addEventListener('DOMContentLoaded', () => {
  // 获取要应的元素
  let addMenu = document.getElementById('addMenu')
  let menuCon = document.getElementById('menuCon')
  let addItem = document.getElementById('addItem')

  // 自定义全局变量存放菜单项
  let menuItem = new Menu()

  // 生成自定义的菜单
  addMenu.addEventListener('click', () => {
    // 创建菜单 
    let menuFile = new MenuItem({ label: '文件', type: 'normal' })
    let menuEdit = new MenuItem({ label: '编辑', type: 'normal' })
    let customMenu = new MenuItem({ label: '自定义菜单项', submenu: menuItem })

    // 将创建好的自定义菜单添加至 menu 
    let menu = new Menu()
    menu.append(menuFile)
    menu.append(menuEdit)
    menu.append(customMenu)

    // 将menu 放置于 app 中显示
    Menu.setApplicationMenu(menu)
  })

  // 动态添加菜单项
  addItem.addEventListener('click', () => {
    // 获取当前 input 输入框当中的内容
    let con = menuCon.value.trim()
    if (con) {
      menuItem.append(new MenuItem({ label: con, type: 'normal' }))
      menuCon.value = ''
    }
  })
})

自定义右键菜单

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 18:55:53  更:2022-06-29 18:57:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 9:50:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码