背景
最近有个需求,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 有以下想法有时间验证下:
- 是否可以拦截 v-on 的 click 事件的注册,拦截到后将对应的元素统一添加 no-drag 样式
- 编写自定义指令,扩展 @click 的功能,同时添加 no-drag 样式
- 是否可以扩展 @click 的修饰符,来将元素上添加 no-drag 样式
- 从 vue-loader 层面检测 template 中的事件并添加相应的 no-drag 样式
上面的猜想实现起来都比较复杂,最简单的还是直接指定 no-drag 样式了,不过假如说代码编写比较规范,比如 点击只是用 button 或者 a 标签,那么剩下的样式应用应该就很少了。
参考文档
本文由 savokiss 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Aug 18, 2019 at 11:23 am
无情小伙