返回介绍

自定义窗口标题栏

发布于 2024-09-11 01:11:55 字数 4915 浏览 0 评论 0 收藏 0

在 src/renderer/components 下新建 BarTop.vue,这是窗口标题栏组件:

<template>
  <div class="topBar">
    <div class="winTitle">{{ title }}}</div>
    <div class="winTool">
      <div @click="minimizeMainWindow">
        <i class="icon icon-minimize"/>
      </div>
      <div v-if="isMaximized" @click="unmaximizeMainWindow">
        <i class="icon icon-restore"/>
      </div>
      <div v-else @click="maxmizeMainWin">
        <i class="icon icon-maximize"/>
      </div>
      <div @click="closeWindow">
        <i class="icon icon-close"/>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
</script>

<style lang="scss" scoped>
.topBar {
  display: flex;
  height: 25px;
  line-height: 25px;
  -webkit-app-region: drag; /* 可拖拽区域 */
  width: 100%;
}

.winTitle {
  flex: 1;
  padding-left: 12px;
  font-size: 14px;
  color: #888;
}

.winTool {
  height: 100%;
  display: flex;
  -webkit-app-region: no-drag; /* 可拖拽区域内的不可拖拽区域 */
}

.winTool div {
  height: 100%;
  width: 34px;
  text-align: center;
  color: #999;
  cursor: pointer;
  line-height: 25px;
}

.winTool .icon {
  font-size: 10px;
  color: #666666;
  font-weight: bold;
}

.winTool div:hover {
  background: #efefef;
}

.winTool div:last-child:hover {
  background: #ff7875;
}

.winTool div:last-child:hover i {
  color: #fff !important;
}
</style>
  • 要自定义一个窗口的标题栏必须把窗口默认的标题栏取消掉才行。只需要在初始化 mainWindow 对象时(主进程里的逻辑),把窗口配置对象的 frame 属性设置为 false 就可以使这个窗口成为无边框窗口了。
  • 窗口标题是通过 props 数据传递给标题栏组件的,也就是说标题栏的标题是由其父组件来确定的。
  • 标题栏中可拖拽区域是通过样式 -webkit-app-region: drag 定义的,鼠标在这个样式定义的组件上拖拽可以移动窗口,双击可以放大或者还原窗口,如果这个组件内有子组件不希望拥有该能力,可以通过 -webkit-app-region: no-drag; 来取消此能力。
  • 最大化、最小化、还原、关闭窗口等按钮的点击事件,都是通过 ipcRenderer.invoke 方法来调用主进程 CommonWindowEvent 类提供的消息管道来实现对应的功能的。
  • 由于窗口最大化(或还原)不一定是通过点击最大化按钮(或还原按钮)触发的,有可能是通过双击标题栏可拖拽区域触发的,所以这里只能通过 ipcRenderer.on 来监听窗口的最大化或还原事件,以此来改变对应的最大化或还原按钮的显隐状态。不能在按钮点击事件中来完成这项工作。windowMaximized 消息和 windowUnmaximized 消息也是由主进程的 CommonWindowEvent 类发来的。
  • 由于多个二级路由页面会引用 BarTop.vue,为了避免在切换路由的时候,反复通过 ipcRenderer.on 注册消息监听器,所以在组件的 onUnmounted 事件内注销了消息监听器,避免事件泄漏。

src/main/CommonWindowEvent.ts 的代码如下:

import { BrowserWindow, ipcMain, app } from 'electron';

// 主进程公共消息处理逻辑
export class CommonWindowEvent {
  private static getWin(event: any) {
    return BrowserWindow.fromWebContents(event.sender);
  }
  public static listen() {
    ipcMain.handle('minimizeWindow', e => {
      this.getWin(e)?.minimize();
    });

    ipcMain.handle('maxmizeWindow', e => {
      this.getWin(e)?.maximize();
    });

    ipcMain.handle('unmaximizeWindow', e => {
      this.getWin(e)?.unmaximize();
    });

    ipcMain.handle('hideWindow', e => {
      this.getWin(e)?.hide();
    });

    ipcMain.handle('showWindow', e => {
      this.getWin(e)?.show();
    });

    ipcMain.handle('closeWindow', e => {
      this.getWin(e)?.close();
    });

    ipcMain.handle('resizable', e => this.getWin(e)?.isResizable());

    ipcMain.handle('getPath', (e, name) => app.getPath(name));
  }

  // 主进程公共事件处理逻辑
  public static regWinEvent(win: BrowserWindow) {
    win.on('maximize', () => {
      win.webContents.send('windowMaximized');
    });
    win.on('unmaximize', () => {
      win.webContents.send('windowUnmaximized');
    })
  }
}
  • 在 listen 方法内部注册了一系列消息管道,方便渲染进程控制主进程的一些行为,标题栏组件的窗口的最大化、最小化、还原等功能都是在这里实现的。在 app ready 之后调用 CommonWindowEvent.listen(); 这个方法即可注册这些消息管道。
  • regWinEvent 方法负责为窗口对象注册事件,当窗口最大化或还原后,这些事件的处理函数负责把消息发送给渲染进程。标题栏的对应按钮的图标也会发生相应的变化,同样也是在 app ready 之后调用 CommonWindowEvent.regWinEvent(mainWindow); 这个方法即可。

在 src/main/mainEntry.ts 下添加如下代码:

import {app, BrowserWindow} from 'electron';
import {CustomScheme} from "./customScheme";
import { CommonWindowEvent } from "./CommonWindowEvent";
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true';
let mainWindow: BrowserWindow;
// 调用 CommonWindowEvent.regWinEvent(win);
app.on("browser-window-created", (e, win) => {
  CommonWindowEvent.regWinEvent(win);
});
app.whenReady().then(() => {
  let config = {
    webPreferences: {
      nodeIntegration: true,
      webSecurity: false,
      allowRunningInsecureContent: true,
      contextIsolation: false,
      webviewTag: true,
      spellcheck: false,
      disableHtmlFullscreenWindowResize: true,
    },
  };
  mainWindow = new BrowserWindow(config);
  mainWindow.webContents.openDevTools({mode: 'undocked'});
  if (process.argv[2]) {
    mainWindow.loadURL(process.argv[2]);
  } else {
    CustomScheme.registerScheme();
    mainWindow.loadURL('app"//index.html');
  }
  // 调用 CommonWindowEvent.listen();
  CommonWindowEvent.listen();
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文