electron 无边框窗口拖拽移动问题记录及解决办法

在做一款uTools的插件,悬浮文本

image

窗口是没有标题栏的,所以需要找一个地方可以拖动移动位置

就开始了接下来的踩坑记录

项目结构

只是一个简单的容器元素,一个多行文本框

容器元素加一个内边距,然后这个内边距区域就是我理想的可拖动位置

<body>
  <div id="container">
    <textarea id="content" spellcheck="false"></textarea>
  </div>
</body>

实现流程

webkit-app-region

首个版本,我采用CSS很简单便实现了

当时是用 Mac 开发测试的,一切运行良好

#container {
	-webkit-app-region: drag;
	padding: 10px;
	cursor: move;
}

隔天到 Win 上看效果

发现拖动虽然正常,但是光标样式没有了

image

鼠标放在边框位置不会变成移动的光标

经查阅,设置了-webkit-app-region: drag;的元素,不会在响应鼠标事件了(mac上测试的时候正常的)

so,需要继续改了

鼠标事件

没有简便办法了,就只好自己写个鼠标拖拽事件了

按下记录下鼠标相对于窗口的位置

鼠标移动后计算出窗口新的位置

窗口新位置=窗口当前位置+鼠标新的相对位置-鼠标原来的相对位置

主进程 (因为是uTools插件开发,和electron原始代码的监听不一样)

ipcRenderer.on('move', (event, x, y) => {
  ubWindow.setPosition(x, y)
})
// 初始化
ipcRenderer.sendTo(ubWindow.webContents.id, 'init')

webPreferencespreload

const { ipcRenderer } = require('electron')
let winId
ipcRenderer.on('init', (event) => {
	winId = event.senderId
	window.init()
})
window.move = (x, y) => {
	ipcRenderer.sendTo(winId,'move',x, y)
}

页面js

let moveIng = false
let startX = 0
let startY = 0
const move = (event) => {
	if (!moveIng) return
	const x = window.screenX + event.clientX - startX
	const y = window.screenY + event.clientY - startY
	window.move(x, y)
}
//绑定拖拽移动事件
document.addEventListener('mousedown', (event) => {
	if (event.button === 0 && event.target.tagName !== 'TEXTAREA') {
		moveIng = true
		startX = event.clientX
		startY = event.clientY
		document.addEventListener('mousemove', move)
	}
})
document.addEventListener('mouseup', (event) => {
	if (!moveIng) return
	document.removeEventListener('mousemove', move)
	moveIng = false
})

测试,Win和Mac拖拽正常,光标正常

image

But,换电脑在测试时,发现某个Win的电脑移动窗口时,窗口尺寸会不停的变大

甚至只要鼠标按在窗口上,尺寸都可能会改变

so,继续改吧

缩放

经过多次测试和查阅

最终把问题定位在Win的缩放与布局

image

该选项如果是100%测试一点问题都没有

如果每次拖动尺寸会发生改变,那我们就不再使用setPosition改用setBounds

每次调整位置时直接将尺寸也传递进去,修改下代码

主进程

ipcRenderer.on('moveBounds', (event, x, y, width, height) => {
  if (event.senderId == ubWindow.webContents.id) {
    let newBounds = {
      x: parseInt(x),
      y: parseInt(y),
      width: parseInt(width),
      height: parseInt(height),
    }
    ubWindow.setBounds(newBounds)
  }
})
// 初始化
ipcRenderer.sendTo(ubWindow.webContents.id, 'init')

webPreferencespreload

const { ipcRenderer } = require('electron')
let winId
ipcRenderer.on('init', (event) => {
	winId = event.senderId
	window.init()
})
window.moveBounds = (x, y, width, height) => {
	ipcRenderer.sendTo(winId, 'moveBounds', x, y, width, height);
}

页面js

let moveIng = false
let startX = 0
let startY = 0
let lastWidth = 0
let lastHeight = 0
const move = (event) => {
  if (!moveIng) return
  const x = window.screenX + event.clientX - startX
  const y = window.screenY + event.clientY - startY
  window.moveBounds(parseInt(x), parseInt(y), lastWidth, lastHeight)
}
//绑定拖拽移动事件
document.addEventListener('mousedown', (event) => {
  if (event.button === 0 && event.target.tagName !== 'TEXTAREA') {
    moveIng = true
    startX = parseInt(event.clientX)
    startY = parseInt(event.clientY)
    lastWidth = parseInt(window.outerWidth)
    lastHeight = parseInt(window.outerHeight)
    document.addEventListener('mousemove', move)
  }
})
document.addEventListener('mouseup', (event) => {
  if (!moveIng) return
  document.removeEventListener('mousemove', move)
  moveIng = false
})

调整后Win和Mac测试均正常

但如果拖动过快,仔细观察,窗口有时会闪烁

而且文本框中的内容有时会变成选中状态

~ o(* ̄▽ ̄*)o 暂时就酱吧

有大神知道更好解决方案的话可以贴出来观摩下

posted @ 2023-06-18 14:07  IT老大哥  阅读(1382)  评论(2编辑  收藏  举报