Skip to content

Electron

安装

bash
npm install --save-dev electron

构建

json
// package.json
{
  "name": "my-app-name",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-builder"
  },
  "build": {
    "appId": "com.example.yourapp",
    "productName": "Your App Name",
    "directories": {
      "output": "dist"
    },
    "files": [
      "dist/**/*",
      "main.js",
      "package.json"
    ],
    "win": {
      "target": "nsis"
    },
    "mac": {
      "target": "dmg"
    },
    "linux": {
      "target": "AppImage"
    }
  },
  "devDependencies": {
    "electron": "^latest-version",
    "electron-builder": "^latest-version"
  }
}

运行

json
// package.json
{
  "scripts": {
    "start": "electron ."
  }
}
bash
npm start

package.json

bash
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "Hello World!",
  "main": "main.js",
  "author": "Vine",
  "license": "MIT"
}

创建一个index.html (渲染进程)

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
    <h1>Hello World!</h1>
    <p>
        We are using Node.js <span id="node-version"></span>,
        Chromium <span id="chrome-version"></span>,
        and Electron <span id="electron-version"></span>.
    </p>
</body>
</html>

创建一个main.js (主进程)

js
const { app, BrowserWindow } = require('electron/main')
const path = require('node:path')

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()

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

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

创建一个preload.js (预加载脚本)

js
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector)
    if (element) element.innerText = text
  }

  for (const type of ['chrome', 'node', 'electron']) {
    replaceText(`${type}-version`, process.versions[type])
  }
})

contentBridge

在proload.js 使用 contentBridge 注入方法 window.electron.startDrag将向主进程发送IPC消息。

js
// proload.js
const { contextBridge, ipcRenderer } = require('electron')
const path = require('node:path')

contextBridge.exposeInMainWorld('electron', {
  startDrag: (fileName) => {
    ipcRenderer.send('ondragstart', path.join(process.cwd(), fileName))
  }
})

Index.html

添加一个可拖动元素到 index.html, 并引用你的渲染器脚本:

<div style="border:2px solid black;border-radius:3px;padding:5px;display:inline-block" draggable="true" id="drag">拖动我</div>
<script src="renderer.js"></script>

Renderer.js

在 renderer.js 通过调用通过上述 contextBridge 添加的方法来设置渲染器进程处理拖动事件。

js
document.getElementById('drag').ondragstart = (event) => {
  event.preventDefault()
  window.electron.startDrag('drag-and-drop.md')
}

打包 使用electron-builder

bash
npm install --save-dev electron-builder
json
// package.json
{
  "scripts": {
    "build": "electron-builder"
  },
  "build": {
    "appId": "com.mycompany.myapp", // 应用程序ID
    "win": {
      "icon": "./logo.ico", // 应用程序图标
      "target": [
        {
          "target": "nsis", // 目标平台
          "arch": [
            "x64" // 生成64位按照包
          ]
        }
      ]
    },
    "nsis":{
      "oneClick": false, // 显示安装向导页面
      "perMachine": true, // 是否允许安装到当前用户的文件夹
      "allowToChangeInstallationDirectory": true // 是否允许用户更改安装目录

    }
  }
}

渲染器对主进程通讯

渲染器进程可以通过调用 contextBridge.exposeInMainWorld 方法将方法暴露给主进程。

js
// preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electron', {
  send: (data) => {
    ipcRenderer.send(data)
  }
})

渲染进程发送消息到主进程

js
// renderer.js
const btn = document.getElementById('btn')
btn.addListener('click', () => {
  window.electron.send('hello')
})

主进程接收消息

js
// main.js
const { BrowserWindow, ipcMain } = require('electron')
function getMessage (event, message) {
  console.log(message) // hello
}
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
    }
  })
  // 在这里处理事件
  ipcMain.on('send', getMessage)

  // 加载页面
  win.loadFile('./pages/index.html')

  // 打开调试器
  win.webContents.openDevTools()
}
app.on('ready', () => {
  createWindow()
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit() // 不是mac系统
})
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

主进程对渲染进程通讯

主进程可以通过调用 ipcMain.handle 方法将方法暴露给渲染进程。

js
// main.js
const { BrowserWindow, ipcMain } = require('electron')
function sendMessage () {
  return 'hello'
}
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
    }
  })
  // 在这里处理事件
  ipcMain.handle('emitsend', sendMessage)

  // 加载页面
  win.loadFile('./pages/index.html')

  // 打开调试器
  win.webContents.openDevTools()
}
app.on('ready', () => {
  createWindow()
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit() // 不是mac系统
})
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

渲染器进程可以通过调用 contextBridge.exposeInMainWorld 方法将方法暴露给主进程。

js
// preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electron', {
  onSend: () => ipcRenderer.invoke('emitsend')
})

渲染器进程获取主进程发送的消息

js
// renderer.js
const btn = document.getElementById('btn')
btn.addListener('click', () => {
  window.electron.onSend().then((data) => {
    console.log(data) // hello
  })

})