当前位置:   article > 正文

Electron 应用开发实践指南 实战篇:自定义窗口的拖拽和缩放_electron 自定义升降

electron 自定义升降

Electron 应用开发实践指南 - muwoo - 掘金小册

前言

默认情况,在构建 Electron BrwoserWindow 的时候,会使用系统自带的原生窗口样式,比如在 MacOS 下的样式:

image.png

在有些情况下,操作系统的原生窗口并不能符合我们的一些视觉和交互需求。所以,在使用 electron 创建桌面应用的时候,有时候我们希望能完全掌控窗口的样式,而隐藏掉系统提供的窗口边框和标题栏等。这个时候就需要用到自定义窗口。

无边框窗口的拖拽

无边框窗口是不带外壳(包括窗口边框、工具栏等),只含有网页内容的窗口。要创建无边框窗口,需在 BrowserWindow 的构造中将 frame 参数设置为 false

 

js

复制代码

// main.js const { BrowserWindow } = require('electron') const win = new BrowserWindow({ frame: false })

image.png

默认情况下,无边框窗口是不可以拖拽的。所以接下来,我们介绍几种让无边框窗口支持拖拽的方式。

1. 使用 -webkit-app-region: drag

应用程序需要在 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>

所以,如果你需要整个窗口所有区域都支持拖拽,那臣妾就做不到了~

2. 自定义拖拽事件

既然 -webkit-app-region: drag 无法做到全屏拖拽移动窗口,那么有没有更好的办法呢?其实另一种方案就是自定拖拽移动,具体怎么做呢?

  1. Electron 需要拖拽的窗口的内容区域监听 mousedown 事件,如果是鼠标左键按下,则开启可拖拽开关 draggable = true。然后记录鼠标按下去的位置 mouseXmouseY
  2. 接下来就启动一个 requestAnimationFrame 函数来把 mouseX 和 mouseY 传递给主进程并不断和主进程通信。
  3. 主进程那边没收到一次通信请求就使用 screen.getCursorScreenPoint() 来获取最新的鼠标位置 x、y。并计算鼠标的位移数值。最后通过 window.setBounds 来重新设置窗口的位置
  4. 监听鼠标的 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 事件,后面就会出现鼠标不管移动到哪里,界面都会跟着,特别烦人!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/936101
推荐阅读
相关标签