Skip to content

窗口定义

窗口管理

向军大叔每晚八点在 抖音bilibli 直播

xj-small

每一个窗口可以简单理解成一个chrome浏览器标签,需要在在electron主文件 electron/main/index.ts 中定义。

  • 窗口可以定义尺寸
  • 窗口可以加载本地文件或一个链接

下面我们创建窗口并加载后盾人网站链接

function createWindow() {
  ...
  const hdWin = new BrowserWindow({
    title: '后盾人',
    width: 390,
    height: 844,
  })
  hdWin.loadURL('https://www.houdunren.com')
  ...
}

下面在项目根据目录创建文件 hd.html ,并使用窗口加载该文件

const hdWin = new BrowserWindow({
  title: '后盾人',
  icon: path.resolve(__dirname, 'favicon.ico')
})
hdWin.loadFile(path.join(__dirname, '../../hd.html'))
hdWin.webContents.openDevTools()

常用方法

下面介绍窗口实例常用的方法

方法说明
win.loadFile()加载文件
win.loadURL()加载链接
win.webContents.openDevTools()打开开发者工具
win.setContentBounds()控制窗口尺寸与位置
win.center()将窗口移动到屏幕中心

常用属性

下面介绍常用的窗口属性

属性说明
title标题,也可以修改html模板的title标签,模板的title标签优先级高
iconwindow系统窗口图标
frame是否显示边框
transparent窗口是否透明
xx坐标
yy坐标
width宽度
height高度
movable是否可以移动窗口
minHeight最小高度,不能缩放小于此高度
minWidth最大高度,不能缩放小于此高度
resizable是否允许缩放窗口
alwaysOnTop窗口是否置顶
autoHideMenuBar是否自动隐藏窗口菜单栏。 一旦设置,菜单栏将只在用户单击 Alt 键时显示
fullscreen是否全屏幕

属性举例

下面演示一些窗口使用的案例

ready-to-show

如果应用过于复杂,在加载本地资源时出现白屏,这时可以监测窗口的 ready-to-show 事件。

  • 设置show属性为false,让窗口不显示
  • 可以通过设置backgroundColor属性指定应用背景颜色,使界面不显示突兀
  • ready-to-show事件检测,当渲染进程绘制完成时,显示窗口
...
const createWindow = () => {
  const win = new BrowserWindow({
    width: 600,
    height: 500,
    show: false,
    backgroundColor: 'red',
  })
  win.loadFile(path.resolve(__dirname, 'index.html'))
  win.once('ready-to-show', () => {
    win.show()
  })
}
...

窗口定位

下面将窗口定位到屏幕右侧顶部,需要使用到 electron 库的 screen对象。

const { app, BrowserWindow, shell, ipcMain, screen } = require('electron')
function createWindow() {
  win = new BrowserWindow({
    title: 'Main window',
    x: screen.getPrimaryDisplay().workAreaSize.width - 414,
    y: 0,
    width: 414,
    height: 736
  })
  ...
}

窗口居中

我们有多种方式实现窗口居中,首先使用 win.center() 方法操作

...
mainWindow.webContents.openDevTools()
mainWindow.loadFile(path.resolve(__dirname, 'index.html'))
mainWindow.center()
...

也可以通过screen模块获取屏幕尺寸,经过计算后设置窗口居中

  • screen.getPrimaryDisplay().workAreaSize 获取窗口尺寸
  • mainWindow.setContentBounds() 设置窗口尺寸与坐标,每二个参数用于定义是否使用过渡动画
...
const mainWindow = new BrowserWindow({
  width: 300,
  height: 300,
  x: 1500,
  y: 100,
  alwaysOnTop: true,
  webPreferences: {
    preload: path.resolve(__dirname, 'preload.js'),
  },
})

mainWindow.webContents.openDevTools()
mainWindow.loadFile(path.resolve(__dirname, 'index.html'))

setTimeout(() => {
  mainWindow.setContentBounds(
    {
      width: 300,
      height: 300,
      x: screen.getPrimaryDisplay().workAreaSize.width / 2 - 150,
      y: 100,
    },
    true,
  )
}, 1000)
...

改变位置

使用 setContentBounds 可以改变窗口的尺寸与位置,第二个参数指定是否使用动画

...
win.loadFile(path.resolve(__dirname, 'index.html'))

setTimeout(() => {
  win.setContentBounds({ height: 100, width: 100, x: 0, y: 0 }, true)
}, 2000)
...

动态修改窗口

下面通过动态修改窗口大小的案例来把窗口属性的使用解释一下。

image-20230214115052070

main.js

const { app, ipcMain, BrowserWindow, screen } = require('electron')
const { createWindow } = require('./window')

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

ipcMain.on('setPostion', (event, options) => {
  //获取窗口
  const win = BrowserWindow.fromWebContents(event.sender)
  //根据屏幕尺寸获取窗口的x坐标,使其居中显示
  const primaryDisplay = screen.getPrimaryDisplay()
  const { width, height } = primaryDisplay.workAreaSize
  const x = width / 2 - options.width / 2
  //设置窗口坐标
  win.setContentBounds({ ...options, x, y: 100 }, true)
})

window.js

该文件用于定义窗口

const { BrowserWindow } = require('electron')
const path = require('path')

const createWindow = () => {
  const mainWindow = new BrowserWindow({
    width: 300,
    height: 300,
    x: 1500,
    y: 100,
    alwaysOnTop: true,
    webPreferences: {
      preload: path.resolve(__dirname, 'preload.js'),
    },
  })

  mainWindow.webContents.openDevTools()
  mainWindow.loadFile(path.resolve(__dirname, 'index.html'))
  return mainWindow
}
module.exports = {
  createWindow,
}

preload.js

预加载脚本用于IPC通信

const { ipcRenderer, contextBridge } = require('electron')

contextBridge.exposeInMainWorld('api', {
  changeWindowPos: (options) => {
    ipcRenderer.send('setPostion', options)
  },
})

renderer.js

渲染进程用于接收按钮事件,然后通过preload.js调用main.js的事件,改变窗口大小。

window.addEventListener('DOMContentLoaded', () => {
  const btn = document.querySelector('button')

  btn.addEventListener('click', () => {
    window.api.changeWindowPos({
      width: Number(document.querySelector('[name="width"]').value),
      height: Number(document.querySelector('[name="height"]').value),
    })
  })
})

index.html

模板文件定义改变窗口的表单

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
    <title>houdunren</title>
  </head>
  <body>
    宽度:<input type="text" name="width" value="500" /> <br />
    调试:<input type="text" name="height" value="500" />
    <button>改变位置</button>
    <script src="renderer.js"></script>
  </body>
</html>

BrowserView

BrowserView 被用来让 BrowserWindow 嵌入更多的 web 内容。 它就像一个子窗口,除了它的位置是相对于父窗口。

下面演示使用 BrowserView 在主窗口中嵌入网页。

const win = new BrowserWindow({
  width: 1024,
  height: 500,
  frame: false,
  webPreferences: {
    preload: path.resolve(__dirname, 'preload.js')
  },
})
win.webContents.openDevTools()
win.loadFile(path.resolve(__dirname, 'index.html'))

const view = new BrowserView()
win.setBrowserView(view)

view.setBounds({
  x: 0,
  y: 0,
  width: win.getBounds().width,
  height: 300,
})
view.webContents.loadURL('https://www.houdunren.com')
image-20230108142236818

Shell

electron的 shell 模块是使用操作系统的默认应用程序打开文件或 url。

可以在 Main, Renderer (只能在非沙盒下使用) 进程中使用

案例分析

下面演示使用 shell 模块,用操作系统的默认浏览器打开网页链接。

index.html 模板文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
    <title>houdunren</title>
  </head>
  <body>
    <a href="https://www.houdunren.com" target="__blank">后盾人</a>
    <script src="renderer.js"></script>
  </body>
</html>

main.js 主进程脚本

const { app, shell } = require('electron')
const { BrowserWindow } = require('electron/main')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 500,
    height: 500,
  })
	
  win.loadFile(path.resolve(__dirname, 'index.html'))
  //捕获a标签的打开事件,使用系统浏览器打开,并阻止新窗口打开
  win.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    //action:deny 拒绝electron新建窗口打开
    //action:allow 允许electron新建窗口打开
    return { action: 'deny' }
  })
}

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