解决Electron拖拽窗口点击事件失效问题
解决方案一
这个拖拽问题导致点击事件失效问题困惑了我好几个晚上,主要还是因为对前端不熟悉。今天问了ChatGPT
它给出了一个解决方案「设置一个透明区域」。
主要代码就是<div class="drag-area"></div>
该标签,该标签占满了整个视口使得整个其都可以拖拽,然后为不可拖拽的元素指定-webkit-app-region: no-drag;
该class 属性。
其实我没有理解这么做为什么可以响应点击事件,因为我尝试过只给 video 标签设置可拖拽,且将 Setting 标签设置为不可拖拽,层级也修改了,但还是无法响应点击事件。
我感觉最重要的应该就是浏览器到底是如何处理透明区域的事件。
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { Setting } from '@icon-park/vue-next'const router = useRouter()
const route = useRoute()const toCameraPage = (query) => {console.log('toCameraPage...')router.push({name: 'camera',query: {...route.query,...query}})
}// 用 ref 引用 video 标签
const video = ref<HTMLVideoElement | null>(null)const constraints = {audio: false,video: true
}onMounted(async () => {if (video.value) {try {const mediaStream = await navigator.mediaDevices.getUserMedia(constraints)video.value.srcObject = mediaStreamvideo.value.onloadedmetadata = function () {video.value?.play()}} catch (error) {console.error('Error accessing media devices.', error)}}
})
</script><template><main class="all"><!-- 兼容拖拽 --><div class="drag-area"></div><Settingclass="setting-icon-wrapper"theme="outline"size="24"fill="#ffffff"@click="toCameraPage"/><video ref="video" class="camera"></video></main>
</template><style lang="less" scoped>
.all {position: relative;/* 确保子元素绝对定位生效 */.drag-area {position: absolute;top: 0;left: 0;width: 100vh;height: 100vh;-webkit-app-region: drag; /* 让整个区域可拖动 */z-index: 1;}.setting-icon-wrapper {position: absolute;cursor: pointer;z-index: 2;top: 3%;left: 50%;transform: translateX(-50%);-webkit-app-region: no-drag;}.camera {height: 100vh;object-fit: cover;}
}
</style>
解决方案二(推荐)
当前解决方案其实是换了一种思路去实现拖拽效果。通过自定义鼠标事件实现
。
-
在渲染进程中注册鼠标事件。
你想让点击哪个元素移动就给哪个元素添加该事件即可;
可拖拽区域完全由你自己控制,即指定元素的大小就是可拖拽区域。<script setup>import { ref } from 'vue'let isKeyDown = ref(false)let dinatesX = ref(0)let dinatesY = ref(0)const mousedown = (e) => {console.log("mousedown...", e)isKeyDown.value = truedinatesX.value = e.xdinatesY.value = e.y// 鼠标移动事件document.onmousemove = (ev) => {if (isKeyDown.value) {console.log("isKeyDown.value", isKeyDown.value)const x = ev.screenX - dinatesX.valueconst y = ev.screenY - dinatesY.value// 每次鼠标按下的时候发生了移动,就给主进程传入坐标// 在主进程中修改当前窗口坐标let coordinate = {appX: x,appY: y,}electron.ipcRenderer.invoke('custom-adsorption', coordinate)}}// 鼠标松开事件document.onmouseup = (ev) => {isKeyDown.value = false}}</script><template><div><div class="drag" @mousedown="mousedown"></div></div> </template><style scoped>.drag {width: 100%;height: 30px;background-color: aqua;} </style>
-
在主进程中监听坐标信息并修改窗口坐标
import { app, shell, BrowserWindow, ipcMain } from 'electron' import { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.png?asset'function createWindow(): void {const mainWindow = new BrowserWindow({width: 900,height: 670,show: false,frame: false, // 无边框窗口autoHideMenuBar: true,...(process.platform === 'linux' ? { icon } : {}),webPreferences: {preload: join(__dirname, '../preload/index.js'),sandbox: false}})// 监听传入的坐标信息,并实时修改窗口坐标ipcMain.handle('custom-adsorption', (_e, coordinate) => {mainWindow.setPosition(coordinate.appX, coordinate.appY)}) }