Electron 无边框窗口开启全局拖拽
in 码农技术宅 with 0 comment

Electron 无边框窗口开启全局拖拽

in 码农技术宅 with 0 comment

背景

最近有个需求,Electron 打开的窗口要实现拖拽功能,大概看了一眼 BrowserWindow 的 API 却只找到了一个 move 事件,这个事件默认是针对有边框窗口的,也即 frame: true 的窗口。

本来打算直接使用 drag API 来写,偶然翻到了以下 API:无边框窗口

其中提到了可拖拽区的概念,即可以将一个矩形区域设置成可拖拽区域,具体文档如下:

文档原文


默认情况下, 无边框窗口是不可拖拽的。 应用程序需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖拽的(如操作系统的标准标题栏),在可拖拽区域内部使用 -webkit-app-region: no-drag 则可以将其中部分区域排除。 请注意, 当前只支持矩形形状。

注意: -webkit-app-region: drag 在开发人员工具打开时会出现问题。 查看更多信息 (包括变通方法), 请参见此 GitHub 问题 。

要使整个窗口可拖拽, 您可以添加 -webkit-app-region: drag 作为 body 的样式:

<body style="-webkit-app-region: drag">
</body>

请注意,如果您使整个窗口都可拖拽,则必须将其中的按钮标记为不可拖拽,否则用户将无法点击它们:

button {
  -webkit-app-region: no-drag;
}

If you're only setting a custom titlebar as draggable, you also need to make all buttons in titlebar non-draggable.


应用

那接下来就简单了,你可以自定义一个 titleBar 区域,将这个区域设置成可拖拽,拖拽操作将会触发 BrowserWindow 的 move 事件。

我们的应用本身就是一个无边框窗口,假如想要整个窗口内容都可以拖拽,就需要设置 body 为 -webkit-app-region: drag,同时将里面的所有需要点击(包括表单元素)需要滚动的元素设置为:-webkit-app-region: no-drag;

下面是目前的做法,添加如下 css 样式:

body {
  -webkit-app-region: drag;
  width: 100%;
  height: 100%;
}

button, a, input, textarea {
  -webkit-app-region: no-drag;
}

.noDrag {
  -webkit-app-region: no-drag;
}

然后在所有需要点击的元素上添加 .noDrag 类,如果一整个父级容器中里面的所有内容有很多需要点击,比如有整个表单,那可以应用到父级容器上,但是要注意应用的容器的高度需要包含内部元素。

高级应用

如果一个应用里有很多需要点击交互的地方,这样添加样式就很麻烦。由于笔者的应用为 Vue.js + Electron 有以下想法有时间验证下:

  1. 是否可以拦截 v-on 的 click 事件的注册,拦截到后将对应的元素统一添加 no-drag 样式
  2. 编写自定义指令,扩展 @click 的功能,同时添加 no-drag 样式
  3. 是否可以扩展 @click 的修饰符,来将元素上添加 no-drag 样式
  4. 从 vue-loader 层面检测 template 中的事件并添加相应的 no-drag 样式

上面的猜想实现起来都比较复杂,最简单的还是直接指定 no-drag 样式了,不过假如说代码编写比较规范,比如 点击只是用 button 或者 a 标签,那么剩下的样式应用应该就很少了。

参考文档

Responses