Electron 窗口等比缩放(按宽高等比例放大缩小)

最近有个需求,做一套基于 Electron 的项目打包工具,并适配老 Web 项目的分辨率及比例,要求窗口缩放按照比例等比放大缩小。

正文

各个项目的适配分辨率不一,而为了伪装成桌面程序,又需要让它们尽量贴满整个窗口并等比缩放,所以这个问题可以拆成两个小问题:

  1. 获得正确分辨率并将 BrowserWindow 初始大小更新为正确分辨率
  2. 拦住窗口的缩放操作,计算等比缩放的窗口大小并应用。

1.获取并设置初始大小

Electron 新建窗口就是新建 BrowserWindow,由于每个 Web 项目的分辨率不同,窗口创建时指定的大小没用,需要在获取到项目分辨率后重新设置窗口大小。

为了不修改老项目的网页代码,我使用 BrowserWindow 构造方法中的 webPreferences.preload 项将 js 文件注入到原来的 html 页面中。

const mainWindow = new BrowserWindow({
    width: 960,
    height: 630,
    // icon:app.getAppPath() + "/favicon.ico",
    icon:path.join(__dirname,"src/TemplateData", 'favicon.ico'),
    webPreferences: {
        preload: path.join(__dirname, '/preload.js'),//此项会在运行时自动注入网页中
        devTools:false,
        nodeIntegration:true
    },
    show:false,
});
mainWindow.loadFile('src/index.html');
mainWindow.once("ready-to-show",()=>{
    mainWindow.show();
})

实际上 preload 加载的 js 文件可以直接调用 node 而无需设置 nodeIntegration。在 preload.js 中获取老项目配置的宽高后,直接通过ipcRenderer发送至后端。

//preload.js
const { ipcRenderer} = require('electron');

window.addEventListener("DOMContentLoaded",OnLoadFinish);
function OnLoadFinish(){
    let realSize = GetRealSize();
    ipcRenderer.send("realSize",realSize);
}
function GetRealSize(){
    //获取 DOM,之后便可以获取其宽高
    //注意,如果宽高是 100px 这种字符串,需要手动将其搞成 Number。
    let mainContent = document.getElementById("xxx");
    let w = mainContent.style.width;
    let h = mainContent.style.height;
    if(typeof(w) == "string"){
      w = parseInt(w.split("px")[0]);
      h = parseInt(h.split("px")[0]);
    }
    return {
        width:w,
        height:h
    }
}

然后,在 Electron 主线程中监听realSize事件,事件触发后重新设置窗口大小。

//main.js
let realSize = null;
ipcMain.once("realSize",(e,args)=>{
    realSize = {width:args.width,height:args.height};
    mainWindow.setMinimumSize(parseInt((args.width) / 2),parseInt((args.height + 30)/2));
    mainWindow.setContentSize(args.width,args.height);//注意此项设置的是ContentSize,此项大小不包括标题栏。
})

2. 缩放时等比缩放

等比缩放很简单,上面已经获取了 realSize,每次将要缩放时,我们拦截住这个请求,并手动设置窗口大小为想要的大小。

Electron 中的 BrowserWindow 在每次重新缩放大小前会触发will-resize事件。

mainWindow.on("will-resize", resizeWindow);

function resizeWindow(event, newBounds){
    if(realSize == null){
        return;
    }
    const win = event.sender;
    event.preventDefault();//拦截,使窗口先不变
    const currentSize = win.getSize();
    const widthChanged = (currentSize[0] != newBounds.width);//判断是宽变了还是高变了,两者都变优先按宽适配
    if(widthChanged){
        win.setContentSize(newBounds.width, parseInt(newBounds.width / (realSize.width / realSize.height) + 0.5));
    } else {
        win.setContentSize(parseInt((realSize.width / realSize.height) * newBounds.height + 0.5), newBounds.height);
    }
}

好了,到这里设置初始化分辨率和等比缩放已经实现了。

3. 其他问题

缩放窗口之后,有时可能需要重新设置 html 中的某些 DOM 样式,可以将相关代码一并写入 preload.js 中。

渲染进程中监听 window 的 resize 事件可以获取窗口大小变化的回调。

//preload.js
window.addEventListener("resize",onResize);
function onResize(){
    //做一些其他事情,例如重新设置div大小,让他等比例铺满窗口
}
梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/6166.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*

0位绅士参与评论

  1. 大坏狐狸04-25 17:19 回复

    前排支持

  2. imbant07-06 17:07 回复

    你好,感谢分享,非常受用的技巧。
    我在 Windows 上尝试拖拽窗口的左边或上边时,setContentSize 的表现比较奇怪;换成 setBounds,重设 x 和 y 效果会好些