# 五、窗口

# 5.1 BrowserWindow

主进程模块BrowserWindow用于创建和控制浏览器窗口。

mainWindow = new BrowserWindow({
  width: 1000,
  height: 800,
  // ...
});
mainWindow.loadURL("http://www.conardli.top/");
1
2
3
4
5
6

你可以在这里 (opens new window)查看它所有的构造参数。

# 5.2 无框窗口

无框窗口是没有镶边的窗口,窗口的部分(如工具栏)不属于网页的一部分。

BrowserWindow的构造参数中,将frame设置为false可以指定窗口为无边框窗口,将工具栏隐藏后,就会产生两个问题:

  • 1.窗口控制按钮(最小化、全屏、关闭按钮)会被隐藏
  • 2.无法拖拽移动窗口

可以通过指定titleBarStyle选项来再将工具栏按钮显示出来,将其设置为hidden表示返回一个隐藏标题栏的全尺寸内容窗口,在左上角仍然有标准的窗口控制按钮。

new BrowserWindow({
  width: 200,
  height: 200,
  titleBarStyle: "hidden",
  frame: false,
});
1
2
3
4
5
6

# 5.3 窗口拖拽

默认情况下, 无边框窗口是不可拖拽的。我们可以在界面中通过CSS属性-webkit-app-region: drag手动制定拖拽区域。

在无框窗口中, 拖动行为可能与选择文本冲突,可以通过设定-webkit-user-select: none;禁用文本选择:

.header {
  -webkit-user-select: none;
  -webkit-app-region: drag;
}
1
2
3
4

相反的,在可拖拽区域内部设置 -webkit-app-region: no-drag则可以指定特定不可拖拽区域。

# 5.4 透明窗口

通过将transparent选项设置为true, 还可以使无框窗口透明:

new BrowserWindow({
  transparent: true,
  frame: false,
});
1
2
3
4

# 5.5 Webview

使用 webview 标签在Electron 应用中嵌入 "外来" 内容。外来内容包含在 webview 容器中。 应用中的嵌入页面可以控制外来内容的布局和重绘。

iframe 不同, webview 在与应用程序不同的进程中运行。它与您的网页没有相同的权限, 应用程序和嵌入内容之间的所有交互都将是异步的。

# 六、对话框

dialog 模块提供了api来展示原生的系统对话框,例如打开文件框,alert框,所以web应用可以给用户带来跟系统应用相同的体验。

注意:dialog 是主进程模块,想要在渲染进程调用可以使用 remote

# 6.1 错误提示

dialog.showErrorBox用于显示一个显示错误消息的模态对话框。

remote.dialog.showErrorBox("错误", "这是一个错误弹框!");
1

# 6.2 对话框

dialog.showErrorBox用于调用系统对话框,可以为指定几种不同的类型: "none", "info", "error", "question" 或者 "warning"。

在 Windows 上, "question" 与"info"显示相同的图标, 除非你使用了 "icon" 选项设置图标。 在 macOS 上, "warning" 和 "error" 显示相同的警告图标

remote.dialog.showMessageBox(
  {
    type: "info",
    title: "提示信息",
    message: "这是一个对话弹框!",
    buttons: ["确定", "取消"],
  },
  (index) => {
    this.setState({
      dialogMessage: `【你点击了${index ? "取消" : "确定"}!!】`,
    });
  }
);
1
2
3
4
5
6
7
8
9
10
11
12
13

# 6.3 文件框

dialog.showOpenDialog用于打开或选择系统目录。

remote.dialog.showOpenDialog(
  {
    properties: ["openDirectory", "openFile"],
  },
  (data) => {
    this.setState({ filePath: `【选择路径:${data[0]}` });
  }
);
1
2
3
4
5
6
7
8

# 6.4 信息框

这里推荐直接使用HTML5 API,它只能在渲染器进程中使用。

let options = {
  title: "信息框标题",
  body: "我是一条信息~~~",
};
let myNotification = new window.Notification(options.title, options);
myNotification.onclick = () => {
  this.setState({ message: "【你点击了信息框!!】" });
};
1
2
3
4
5
6
7
8

# 七、系统

# 7.1 获取系统信息

通过remote获取到主进程的process对象,可以获取到当前应用的各个版本信息:

  • process.versions.electronelectron版本信息
  • process.versions.chromechrome版本信息
  • process.versions.nodenode版本信息
  • process.versions.v8v8版本信息

获取当前应用根目录:

remote.app.getAppPath();
1

使用nodeos模块获取当前系统根目录:

os.homedir();
1

# 7.2 复制粘贴

Electron提供的clipboard在渲染进程和主进程都可使用,用于在系统剪贴板上执行复制和粘贴操作。

以纯文本的形式写入剪贴板:

clipboard.writeText(text[, type])
1

以纯文本的形式获取剪贴板的内容:

clipboard.readText([type]);
1

# 7.3 截图

desktopCapturer用于从桌面捕获音频和视频的媒体源的信息。它只能在渲染进程中被调用。

下面的代码是一个获取屏幕截图并保存的实例:

getImg = () => {
  this.setState({ imgMsg: "正在截取屏幕..." });
  const thumbSize = this.determineScreenShotSize();
  let options = { types: ["screen"], thumbnailSize: thumbSize };
  desktopCapturer.getSources(options, (error, sources) => {
    if (error) return console.log(error);
    sources.forEach((source) => {
      if (source.name === "Entire screen" || source.name === "Screen 1") {
        const screenshotPath = path.join(os.tmpdir(), "screenshot.png");
        fs.writeFile(screenshotPath, source.thumbnail.toPNG(), (error) => {
          if (error) return console.log(error);
          shell.openExternal(`file://${screenshotPath}`);
          this.setState({ imgMsg: `截图保存到: ${screenshotPath}` });
        });
      }
    });
  });
};

determineScreenShotSize = () => {
  const screenSize = screen.getPrimaryDisplay().workAreaSize;
  const maxDimension = Math.max(screenSize.width, screenSize.height);
  return {
    width: maxDimension * window.devicePixelRatio,
    height: maxDimension * window.devicePixelRatio,
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 八、菜单

应用程序的菜单可以帮助我们快捷的到达某一功能,而不借助客户端的界面资源,一般菜单分为两种:

  • 应用程序菜单:位于应用程序顶部,在全局范围内都能使用
  • 上下文菜单:可自定义任意页面显示,自定义调用,如右键菜单

Electron为我们提供了Menu模块用于创建本机应用程序菜单和上下文菜单,它是一个主进程模块。

你可以通过Menu的静态方法buildFromTemplate(template),使用自定义菜单模版来构造一个菜单对象。

template是一个MenuItem的数组,我们来看看MenuItem的几个重要参数:

  • label:菜单显示的文字
  • click:点击菜单后的事件处理函数
  • role:系统预定义的菜单,例如copy(复制)、paste(粘贴)、minimize(最小化)...
  • enabled:指示是否启用该项目,此属性可以动态更改
  • submenu:子菜单,也是一个MenuItem的数组

推荐:最好指定 role 与标准角色相匹配的任何菜单项,而不是尝试手动实现 click 函数中的行为。内置 role 行为将提供最佳的本地体验。

下面的实例是一个简单的额菜单template

const template = [
  {
    label: "文件",
    submenu: [
      {
        label: "新建文件",
        click: function () {
          dialog.showMessageBox({
            type: "info",
            message: "嘿!",
            detail: "你点击了新建文件!",
          });
        },
      },
    ],
  },
  {
    label: "编辑",
    submenu: [
      {
        label: "剪切",
        role: "cut",
      },
      {
        label: "复制",
        role: "copy",
      },
      {
        label: "粘贴",
        role: "paste",
      },
    ],
  },
  {
    label: "最小化",
    role: "minimize",
  },
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 8.1 应用程序菜单

使用Menu的静态方法setApplicationMenu,可创建一个应用程序菜单,在 WindowsLinux 上,menu将被设置为每个窗口的顶层菜单。

注意:必须在模块 ready 事件后调用此 API app。

我们可以根据应用程序不同的的生命周期,不同的系统对菜单做不同的处理。

app.on("ready", function () {
  const menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
});

app.on("browser-window-created", function () {
  let reopenMenuItem = findReopenMenuItem();
  if (reopenMenuItem) reopenMenuItem.enabled = false;
});

app.on("window-all-closed", function () {
  let reopenMenuItem = findReopenMenuItem();
  if (reopenMenuItem) reopenMenuItem.enabled = true;
});

if (process.platform === "win32") {
  const helpMenu = template[template.length - 1].submenu;
  addUpdateMenuItems(helpMenu, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 8.2 上下文菜单

使用Menu的实例方法menu.popup可自定义弹出上下文菜单。

let m = Menu.buildFromTemplate(template);
document
  .getElementById("menuDemoContainer")
  .addEventListener("contextmenu", (e) => {
    e.preventDefault();
    m.popup({ window: remote.getCurrentWindow() });
  });
1
2
3
4
5
6
7

# 8.3 快捷键

在菜单选项中,我们可以指定一个accelerator属性来指定操作的快捷键:

  {
    label: '最小化',
    accelerator: 'CmdOrCtrl+M',
    role: 'minimize'
  }
1
2
3
4
5

另外,我们还可以使用globalShortcut来注册全局快捷键。

globalShortcut.register("CommandOrControl+N", () => {
  dialog.showMessageBox({
    type: "info",
    message: "嘿!",
    detail: "你触发了手动注册的快捷键.",
  });
});
1
2
3
4
5
6
7

CommandOrControl 代表在 macOS 上为 Command 键,以及在 Linux 和 Windows 上为 Control 键。

文中如有错误,欢迎在评论区指正,如果这篇文章帮助到了你,欢迎点赞和关注。