家政公司网站的建设,南京网络推广网站建设公司,煤矿网站建设,湖北设计公司在开发 Electron 应用时#xff0c;可能需要创建完全透明的窗口#xff0c;比如我们要做一个屏幕内容共享的功能#xff0c;在特定矩形区域内的内容才会被共享出来#xff0c;而这个区域是一个透明且可被穿透的区域。
首先我们需要再主进程上创建一个矩形窗口
const scre…在开发 Electron 应用时可能需要创建完全透明的窗口比如我们要做一个屏幕内容共享的功能在特定矩形区域内的内容才会被共享出来而这个区域是一个透明且可被穿透的区域。
首先我们需要再主进程上创建一个矩形窗口
const screenRegionShareWindow new BrowserWindow({width: 800,height: 600,// 关键创建无边框窗口没有窗口的某些部分例如工具栏、控件等frame: false,// 关键创建一个完全透明的窗口transparent: true,minHeight: Math.ceil(workAreaSize.height * 0.3),minWidth: Math.ceil(workAreaSize.width * 0.3),// 窗口可移动movable: true,// 窗口可调整大小resizable: true,// 窗口不能最小化minimizable: false,// 窗口不能最大化maximizable: false,// 窗口不能进入全屏状态fullscreenable: false,// 窗口不能关闭closable: true,webPreferences: {nodeIntegration: true,contextIsolation: false // 否则页面无法用require}});共享区域的窗口一定是透明的、可移动的、并且没有边框、可调整大小但不能最小化和最大化也不能进入全屏状态窗口也不能在程序坞中关闭。
实现点击穿透
要创建一个点击穿透窗口也就是使窗口忽略所有鼠标事件可以调用 win.setIgnoreMouseEvents(ignore) API
screenRegionShareWindow.setIgnoreMouseEvents(true)设置可拖动元素
默认情况下, 无边框窗口是不可拖拽的。 应用程序需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖拽的如操作系统的标准标题栏在可拖拽区域内部使用 -webkit-app-region: no-drag 则可以将其中部分区域排除。
要使整个窗口可拖拽, 您可以添加 -webkit-app-region: drag 作为 body 的样式:
body {-webkit-app-region: drag;
}前端部分实现如下
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headstylehtml,body {margin: 0;padding: 0;background: transparent;}.container {margin: 0px;padding: 0px;width: 100vw;height: 100vh;pointer-events: none;position: relative;background: transparent;}.line {background: #3876ff;-webkit-app-region: drag;cursor: move;position: absolute;pointer-events: auto;}.line1 {height: 24px;top: 0;left: 0;right: 0;}.line2 {height: 4px;bottom: 0;left: 0;right: 0;}.line3 {width: 4px;bottom: 0;left: 0;top: 0;}.line4 {width: 4px;bottom: 0;right: 0;top: 0;}#center {position: absolute;left: 4px;bottom: 4px;right: 4px;top: 24px;pointer-events: auto;}/stylebodydiv classcontainerdiv classline line1/divdiv classline line2/divdiv classline line3/divdiv classline line4/divdiv idcenter/div/div/bodyscriptconst $ document.querySelector.bind(document);const centerElm $(#center);const ipcRenderer require(electron).ipcRenderer;centerElm.addEventListener(mouseenter,() {console.log(enter);ipcRenderer.send(ignoreMouseEvent, true);},false);centerElm.addEventListener(mouseleave,() {console.log(leave);ipcRenderer.send(ignoreMouseEvent, false);},false);/script
/html主进程代码
ipcMain.on(ignoreMouseEvent,(event, ignore){if(ignore){screenRegionShareWindow?.setIgnoreMouseEvents(true, { forward: true });}else{screenRegionShareWindow?.setIgnoreMouseEvents(false);}
});上面代码我们设置了鼠标进入的时候只有点击事件会穿透窗口鼠标移动事件仍会触发forward: true的作用当鼠标离开窗口后就不再忽略鼠标事件。
除此之外我们还在 CSS 上的透明区域.container禁用鼠标事件该元素就永远不会成为鼠标事件的target了而给 .line 和 .center 部分设置 pointer-events: auto; 让它们还可以成为鼠标事件的 target。
.line 是窗口的边框并且设置 -webkit-app-region: drag; 让四周的边框可以拖动并且跟随鼠标移动。
给 .center 元素设置 pointer-events: auto; 可以监听到鼠标事件由因为我们设置了点击穿透因此鼠标事件会被传递到此窗口下面的窗口。
计算共享区域的大小
当窗口移动或者调整矩形区域大小时我们需要更新窗口位置然后获取新的屏幕像素信息。
核心代码
function getContentWindowPhysicalRect() {let rect { x: 0, y: 0, width: 0, height: 0 };if (screenRegionShareWindow) {const { x, y, width, height } screenRegionShareWindow.getContentBounds();rect screen.dipToScreenRect(null, {x: Math.ceil(x 4) 1,y: Math.ceil(y 24) 1,width: Math.floor(width - 8) - 1,height: Math.floor(height - 28) - 1,});}return rect;
}首先调用 getContentBounds() API 获取到窗口的位置和大小然后调用 dipToScreenRect 将屏幕DIP设备独立像素矩阵转换为屏幕物理矩阵。 可以把 DIP 的单位理解为浏览器中的 px如果屏幕像素比DPR是2则代表 1px 2个物理像素用 dipToScreenRect 转了之后 rect 中的值会变大。
然后就是窗口移动或者缩放时调用 getContentWindowPhysicalRect 即可。
screenRegionShareWindow.on(resized, () {updateContentRegion();
});screenRegionShareWindow.on(moved, () {updateContentRegion();
});// 移动之前应该先把共享暂停然后 moved 之后再更新共享区域
screenRegionShareWindow.on(will-move, () {mainWindow?.webContents.send(regionSharingWindowWillChange);
});screenRegionShareWindow.on(will-resize, () {mainWindow?.webContents.send(regionSharingWindowWillChange);
});移动或者更新窗口大小之前应该先把共享暂停然后 moved/resized 之后再更新共享区域不然在移动的时候在共享画面那能看到边框。