赞
踩
默认情况,在构建 Electron BrwoserWindow
的时候,会使用系统自带的原生窗口样式,比如在 MacOS
下的样式:
在有些情况下,操作系统的原生窗口并不能符合我们的一些视觉和交互需求。所以,在使用 electron
创建桌面应用的时候,有时候我们希望能完全掌控窗口的样式,而隐藏掉系统提供的窗口边框和标题栏等。这个时候就需要用到自定义窗口。
无边框窗口是不带外壳(包括窗口边框、工具栏等),只含有网页内容的窗口。要创建无边框窗口,需在 BrowserWindow
的构造中将 frame
参数设置为 false
:
js
复制代码
// main.js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ frame: false })
默认情况下,无边框窗口是不可以拖拽的。所以接下来,我们介绍几种让无边框窗口支持拖拽的方式。
应用程序需要在 CSS 中指定 -webkit-app-region: drag
来告诉 Electron 哪些区域是可拖拽的(如操作系统的标准标题栏),当前只支持矩形形状区域。
html
复制代码
<body style="-webkit-app-region: drag"></body>
注意:在某部分 windows 上使用 -webkit-app-region: drag
来设置拖拽,那么请记住需要在可拖拽区域内部使用 -webkit-app-region: no-drag
来将其中部分需要交互的区域排除。不然那些需要交互的元素几乎无法响应所有的鼠标事件,包括点击、拖拽等。
html
复制代码
<body style="-webkit-app-region: drag"> <button style="-webkit-app-region: no-drag;">click</button> </body>
所以,如果你需要整个窗口所有区域都支持拖拽,那臣妾就做不到了~
既然 -webkit-app-region: drag
无法做到全屏拖拽移动窗口,那么有没有更好的办法呢?其实另一种方案就是自定拖拽移动,具体怎么做呢?
mousedown
事件,如果是鼠标左键按下,则开启可拖拽开关 draggable = true
。然后记录鼠标按下去的位置 mouseX
、mouseY
。requestAnimationFrame
函数来把 mouseX
和 mouseY
传递给主进程并不断和主进程通信。screen.getCursorScreenPoint()
来获取最新的鼠标位置 x、y
。并计算鼠标的位移数值。最后通过 window.setBounds
来重新设置窗口的位置mouseup
事件,如果触发,则设置 draggable=false
。防止意外拖拽的产生。对应到代码的实现:
js
复制代码
// renderer/dragWindow.js import { ipcRenderer } from 'electron'; const useDrag = () => { let animationId; let mouseX; let mouseY; let clientWidth = 0; let clientHeight = 0; let draggable = true; const onMouseDown = (e) => { // 右击不移动,只有左击的时候触发 if (e.button === 2) return; draggable = true; // 记录位置 mouseX = e.clientX; mouseY = e.clientY; // 记录窗口大小 if (Math.abs(document.body.clientWidth - clientWidth) > 5) { clientWidth = document.body.clientWidth; } if (Math.abs(document.body.clientHeight - clientHeight) > 5) { clientHeight = document.body.clientHeight; } // 注册 mouseup 事件 document.addEventListener('mouseup', onMouseUp); // 启动通信 animationId = requestAnimationFrame(moveWindow); }; const onMouseUp = () => { // 释放锁 draggable = false; // 移除 mouseup 事件 document.removeEventListener('mouseup', onMouseUp); // 清除定时器 cancelAnimationFrame(animationId); }; const moveWindow = () => { // 传给主进程位置信息 ipcRenderer.send('msg-trigger', { type: 'windowMoving', data: { mouseX, mouseY, width: clientWidth, height: clientHeight }, }); if (draggable) animationId = requestAnimationFrame(moveWindow); }; return { onMouseDown, }; }; export default useDrag;
js
复制代码
// main.js public windowMoving({ data: { mouseX, mouseY, width, height } }, window, e) { // 获取当前鼠标的绝对位置。 const { x, y } = screen.getCursorScreenPoint(); // 获取当前需要移动的窗口 const originWindow = this.getCurrentWindow(window, e); if (!originWindow) return; // 重新设置窗口位置 originWindow.setBounds({ x: x - mouseX, y: y - mouseY, width, height }); }
但这么做也有一些问题,首先就是渲染进程需要主进程直接进行通信,通信需要一定时间,所以窗口的移动必然慢于鼠标的移动,会造成一定程度的卡顿。其次,只能通过 document.removeEventListener('mouseup')
的方法来注销对鼠标移动事件的监听,这个跟第一点接到一起就可能出现这样一种情况:鼠标移动得太快,界面没来得及跟得上,导致鼠标在界面外部释放,未能触发 mouseup
事件,后面就会出现鼠标不管移动到哪里,界面都会跟着,特别烦人!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。