Electron 读取本地配置 增加缩放功能(ctrl+scroll)

最近,一个之前做的electron桌面应用,需要增加两个功能;第一是读取本地的配置文件,然后记载配置文件中的ip地址;第二就是增加缩放功能;

第一,配置本地文件

首先需要在vue工程根目录中,新建一个config.json文件;如下图

config.json内容如下:

javascript 复制代码
{
  "ip": "1.11.21.219",
  "port": 30002,
}

然后在vue.config.js中需要排除这个文件,如下:

javascript 复制代码
    // 添加electron - app -icon
    pluginOptions: {
        electronBuilder: {
            builderOptions: {
                productName: 'xxxx', //项目名,也是生成的安装文件名
                //copyright: "Copyright © 2019",//版权信息
                win: {
                    icon: './public/favicon.ico',
                    // 以管理员权限运行
                    requestedExecutionLevel: 'requireAdministrator',
                    target: [{
                        target: "nsis", //利用nsis制作安装程序
                        arch: [
                            "x64", //64位
                        ]
                    }],
                    
                },
                nsis: {
                    oneClick: false, // 是否一键安装
                    allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
                    allowToChangeInstallationDirectory: true, // 允许修改安装目录
                    installerIcon: "./public/favicon.ico", // 安装图标
                    uninstallerIcon: "./public/favicon.ico", //卸载图标
                    installerHeaderIcon: "./public/favicon.ico", // 安装时头部图标
                    createDesktopShortcut: true, // 创建桌面图标
                    createStartMenuShortcut: true, // 创建开始菜单图标
                    shortcutName: "MIES", // 图标名称
                },
                directories: {
                    output: "./MIES_SETUP" //输出文件路径
                },



                /**** 注意这里 配置config.json ****/





                extraResources: [
                    { "from": "./config.json", "to": "../" }
                ],
            },
            nodeIntegration: true,
            preload: 'src/preload.js'
        }
    },
    // 

然后,安装桌面应用之后,会在安装目录出现这个配置好的config.json.

第二,读取本地配置文件,创建window

在backgroundjs中,使用nodejs的fs模块读取根目录下的config.json文件,动态获取配置的ip和端口,然后创建window。

代码如下:

javascript 复制代码
............







// Create the browser window.
let win = null;

async function createWindow() {
  // 读取信息
  var exePath = path.dirname(app.getPath("exe")).replace(/\\/g, "/");
  // console.log(exePath);
  var configPath = `${exePath}/config.json`;

  var sockets = [];


   // ********************   这里是主要功能   ************************* //
   // 读取本地文件 获取配置信息

  fs.readFile(configPath, "utf-8", async (err, data) => {
    if (data) {
      const cp = require("child_process");
      let res = JSON.parse(data);
      const PAGE_URL = `https://${res.ip}:${res.port}`;
      // 创建窗口
      win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          // Use pluginOptions.nodeIntegration, leave this alone
          // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
          // process.env.ELECTRON_NODE_INTEGRATION
          nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
          contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
          preload: path.join(__dirname, "/preload.js"),
          webSecurity: false,
          allowRunningInsecureContent: false,
          //zoomFactor: 0.6,
        },
        icon: path.join(__dirname, "./favicon.ico"),
      });

      if (process.env.WEBPACK_DEV_SERVER_URL) {
        // Load the url of the dev server if in development mode
        //await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
        console.log("PAGE_URL ----- ", PAGE_URL);
        await win.loadURL(PAGE_URL);
        if (!process.env.IS_TEST) win.webContents.openDevTools();
      } else {
        createProtocol("app");
        // Load the index.html when not in development
        // win.loadURL('app://./index.html');
        //win.loadURL(path.join(__dirname, "./index.html"));
        // https://www.electronjs.org
        console.log("PAGE_URL ----- ", PAGE_URL);
        win.loadURL(PAGE_URL);
      }

      //进入软件即开启全屏
      //win.setFullScreen(true);

      // 最大化
      win.maximize();

      //配置ESC键退出全屏 ESC
      globalShortcut.register("Alt+CommandOrControl+Q", () => {
        win.setFullScreen(false);
      });

      // 配置设置快捷键
      globalShortcut.register("Alt+CommandOrControl+S", () => {
        win.webContents.send("asynchronous-message", "123");
      });

      // ctrl_alt_f 打开全屏设置
      globalShortcut.register("Alt+CommandOrControl+F", () => {
        win.setFullScreen(true);
      });

      // 主进程缩小窗口
      ipcMain.on("window-min", function() {
        // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        win.minimize();
      });

      // ctrl_alt_i 手动打开开发者工具
      globalShortcut.register("Alt+CommandOrControl+I", () => {
        win.webContents.openDevTools({
          mode: "bottom",
        });
      });

      // 获取安装地址
      // globalShortcut.register('Alt+CommandOrControl+P', () => {
      //     win.webContents.send("asynchronous-message", path.dirname(app.getPath('exe')));
      // })

      // 手动打开开发者工具
      // ipcMain.on('open-dev', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
      //     win.webContents.openDevTools({
      //         mode: 'bottom'
      //     })
      // })

      // 设置顶部菜单
      // 自定义一些菜单
      const appMenuTemplate = [
        {
          label: "窗口",
          submenu: [
            {
              label: "打开全屏",
              click: () => {
                win.setFullScreen(true);
              },
            },
            {
              label: "退出全屏",
              click: () => {
                win.setFullScreen(false);
              },
            },
          ],
        },
        {
          label: "设置",
          submenu: [
            // {
            //   label: "设置首页",
            //   click: () => {
            //     win.webContents.send("asynchronous-message", "123");
            //   },
            // },
            {
              label: "强制刷新",
              role: "forceReload",
            },
            {
              label: "退出",
              role: "quit",
            },
            {
              label: "开发者选项",
              click: () => {
                win.webContents.openDevTools({
                  mode: "bottom",
                });
              },
            },
          ],
        },
      ];

      const menu = Menu.buildFromTemplate(appMenuTemplate);
      Menu.setApplicationMenu(menu);

      // 窗口关闭的监听
      win.on("closed", (event) => {
        win = null;
      });

      // 点击关闭
      win.on("close", (event) => {
        const closeWinFlagValue = dialog.showMessageBoxSync(win, {
          type: "info",
          buttons: ["最小化到托盘", "直接退出", "取消"],
          title: "提示",
          message: "确定要退出吗?",
          defaultId: 0,
          cancelId: 2,
        });
        console.log("closeWinFlagValue", closeWinFlagValue);
        event.preventDefault();
        if (closeWinFlagValue === 0) {
          // 托盘对象
          var appTray = null;
          // 系统托盘右键菜单
          var trayMenuTemplate = [
            {
              label: "显示",
              click: function() {
                !win.isVisible() ? win.show() : null;
              },
            },
            {
              label: "退出",
              click: function() {
                app.quit();
              },
            },
          ];
          win.hide();
          // 系统托盘图标目录 path.join(__static, './logo_1.ico')
          let trayIcon = path.join(__dirname, "./favicon.ico");

          appTray = new Tray(trayIcon);

          // 图标的上下文菜单
          const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);

          // 设置此托盘图标的悬停提示内容
          appTray.setToolTip("上海局高铁机务管理智能评价系统");

          // 设置此图标的上下文菜单
          appTray.setContextMenu(contextMenu);

          // 单击击托盘显示隐藏
          appTray.on("click", () => {
            win.isVisible() ? win.hide() : win.show();
            // 关闭托盘显示
            appTray.destroy();
            appTray = null;
          });
        } else if (closeWinFlagValue === 1) {
          app.exit();
        } else if (closeWinFlagValue === 2) {
          win.focus();
          win.show();
        }
      });

      // 设置托盘
      // Exit cleanly on request from parent process in development mode.

      if (process.platform === "win32") {
        /* process.on('message', (data) => {
            if (data === 'graceful-exit') {
                app.quit()
            }
        }) */
      } else {
        process.on("SIGTERM", () => {
          app.quit();
        });
      }

      // D:/dev_tools/MIES
      //console.log('读取本地文件 == ', res);
      // let socketPath = exePath + "/WebMiddleware.exe";
      // //let child = cp.spawn(socketPath, [res.ip, res.port])
      // cp.exec(`${socketPath} ${res.ip} ${res.port}`, (err, stdout, stderr) => {
      //   console.log("err, stdout, stderr", err, stdout, stderr);
      // });

      // 向vue发送配置的wsip和端口
      let ws_path = `wss://${res.ws_ip}:${res.ws_port}`;
      const http = require("http"); // 创建服务器对象
      const server = http.createServer();
      const closeServer = () => {
        sockets.forEach(function(socket) {
          socket.destroy();
        });
        server.close(function() {
          console.log("close server!");
        });
      };
      server.listen(res.local_port); // 对错误进行捕获
      server.on("error", (err) => {
        if (err.code == "EADDRINUSE") {
          // 如果目标端口被占用将使用
          // NodeJS 随机分配的端口号
          server.listen(0);
        }
      }); // 在成功监听后,向终端输出被监听的端口号
      server.on("listening", () => {
        console.log(
          "【HTTP Server is running at http://127.0.0.1:" +
            server.address().port +
            " 】"
        );
      });
      server.on("connection", function(socket) {
        sockets.push(socket);
        //console.log('sockets', sockets);
        socket.once("close", function() {
          sockets.splice(sockets.indexOf(socket), 1);
        });
      });
      server.on("request", function(req, res) {
        const url = req.url;
        if (url === "/getWsPath") {
          res.setHeader("content-type", "application/json");
          res.end(ws_path);
          closeServer();
        } else {
          res.writeHeader(404);
          res.end("404 not found");
          closeServer();
        }
      });
    }
  });
}

至此就可以完成读取本地文件,获取配置信息功能。

第三,完成缩放功能

需求要求实现和浏览器一样,ctrl加上鼠标滚轮,可以完成页面的缩放,具体代码如下:

javascript 复制代码
let level = 0;
      // 缩放
      win.webContents.on('zoom-changed',(e, zoomDirection)=>{
        if (zoomDirection === 'in') {
          level = level >= 3 ? level : level += 0.2
        } else {
          level = level <= -3 ? level : level -= 0.2
        }
        win.webContents.setZoomLevel(level)
      })
相关推荐
TrisighT8 分钟前
Electron 跑在鸿蒙 PC 上,单窗口和多窗口内存差 800MB?我抓了 5 组数据
性能优化·electron·harmonyos
竹林8189 分钟前
用 wagmi v2 + viem 监听链上事件,我踩了三天坑终于搞懂了实时日志与历史补全
javascript
Momo__13 分钟前
VueUse createReusableTemplate —— 单文件组件内的模板复用神器
前端·vue.js
只一16 分钟前
😭从回调地狱到 async/await:一文打通 Ajax 与 JS 异步编程
javascript
程序员小富19 分钟前
我开源了一个开发者专属的智能 JSON 工具,得到了媳妇高度认可
前端·vue.js·后端
小小小小宇20 分钟前
程序员如何给 LLM 装工具以及看懂推理过程
前端
写代码的皮筏艇20 分钟前
React中的forwardRef
前端·react.js·面试
槑有老呆28 分钟前
花三个月工资请了个 AI 程序员,结果它连青岛啤酒股价都查不了
前端
风骏时光牛马30 分钟前
Verilog开发常见问题汇总解析
前端
子兮曰32 分钟前
AI Coding Method Map:一张图看懂 AI 编程的完整链路
前端·人工智能·后端