# 🚀Electron创建圆角窗口

📅 2023/5/15

# 无边框窗口

我们在开发桌面应用程的过程中,大部的时候是不希望使用默认的标题栏的,因此我们需要将标题栏隐藏并重新绘制标题栏。可以通过将frame设置为false来隐藏标题栏。

new BrowserWindow({
    frame:false
})

在隐藏默认标题栏后,如果我们想要拖动窗口,需要在可拖动区域的元素上增加 -webkit-app-region: drag 的css 属性。

.drag{
    -webkit-app-region: drag;
}

但是需要注意,当添加该属性后,其自身和包含的子元素鼠标事件都将失效,如果需要添加鼠标事件,可以在需要绑定事件的元素上增加 -webkit-app-region: no-drag 的css属性。

.no-drag{
    -webkit-app-region: no-drag;
}

# 透明窗口

创建圆角窗口的前提是必选是无边框窗口,及frame属性必须为false(windows上),在此基础上增加transparent:true的属性。

new BrowserWindow({
    frame:false,
    transparent:true
})

窗口设置透明后,则可以在页面上创建一个主DIV区域,并设置其背景色和圆角来实现视觉上的圆角窗口。这里建议将body的滚动条禁用。

body,html{
    overflow: hidden;
}

# 透明窗口的点击穿透

有些时候我们在创建不规则窗口的时候,需要在透明区域进行点击穿透。 例如:我们创建一个圆形窗口,虽然视觉上创建的窗口为圆形,但是实际上还是一个方形窗口,只不过透明了而已。这样就会导致圆形以外,方形以内会出现一部分透明但不可点击的区域,阻止用户点击被其覆盖的桌面区域。具体情况如图。
需要点击穿透情况示例
虽然官方表示无法完成该种操作,但是可以通过一些小技巧实现。
首先,我们需要用到窗口对象的setIgnoreMouseEvents方法,该方法可以使窗口忽略窗口内的所有鼠标事件,并且在此窗口中发生的所有鼠标事件都将被传递到此窗口背后的内容上。如果调用该方法时传递了forward参数,如setIgnoreMouseEvents(true, { forward: true }),则只有点击事件会穿透窗口,鼠标移动事件仍会正常触发。

# 渲染进程

const {ipcRenderer} = require('electron')
window.addEventListener("mousemove",event => {
    const flag = event.target === document.documentElement
    ipcRenderer.send('penetrateWin',flag)
})
ipcRenderer.send('penetrateWin',true)
body,
html {
    pointer-events: none;
}
#app {
    pointer-events: auto;
}

# 主进程

 ipcMain.on('penetrateWin',(event,flag)=>{
    if(flag){
        win.setIgnoreMouseEvents(true, { forward: true })
    }else{
        win.setIgnoreMouseEvents(false)
    }
})

渲染进程即你的页面上设置整体 pointer-events: none来禁止响应鼠标事件,然后在操作区域即你的视觉区域通过pointer-events: auto恢复鼠标响应事件。这样就做到排除窗口中透明且不可见区域的鼠标响应事件;然后监听鼠标移动事件来判断鼠标是否在可视窗口上,并将该结果发送至主进程。
主进程在接收到消息后,如果鼠标在圆形窗口(或其他形状的窗口上时,则设置当前窗口不可穿透),否则设置为可穿透,这样就实现了透明窗口的点击穿透。
由于鼠标移动事件触发频繁,这里应该使用节流/防抖函数进行监听,或者通过其他方法,例如在穿透和不可穿透状态切换时才触发来减少通信次数。但是最好在开发过程中还是不要使用这种窗口。