Electron Vue之间的通讯 自定义标题栏实现最小化全屏关闭功能

news2024/11/17 21:51:59

方便以后定制化使用,学习记录一下。
话不多说,先看看效果吧。

效果

img

版本

  • electron ^13.0.0

知识点

Vue 相互通讯 Electron 标题栏主要逻辑代码

新建public\preload.js文件,用于前端全局发送和监听消息。

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
    minimize: () => ipcRenderer.send('minimize'),
    windowization: () => ipcRenderer.send('windowization'),
    maximize: () => ipcRenderer.send('maximize'),
    quit: () => ipcRenderer.send('quit'),
    onIsMaximizable: (callback) => ipcRenderer.on('is-maximizable', callback)
})

修改src\background.js文件,用于Electron接受发送消息。

async function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    // 框架隐藏
    frame: false,
    webPreferences: {
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
      preload: process.env.WEBPACK_DEV_SERVER_URL ? path.join(__dirname, 'bundled', 'preload.js') : path.join(__dirname, 'preload.js')
    }
  })


  win.on('maximize', (event) => {
    console.log("窗口最大化")
    win.webContents.send('is-maximizable', true)
  })
  win.on('resize', (event) => {
    console.log("窗口还原");
    win.webContents.send('is-maximizable', win.isMaximized())
  })
}

ipcMain.on('minimize', (event) => {
  win.minimize()
})
ipcMain.on('quit', (event) => {
  app.quit()
})
ipcMain.on('maximize', (event) => {
  win.maximize()
})
ipcMain.on('windowization', (event) => {
  win.restore();
})

关于打包构建调试,preload.js加载路径可能不同,所以需要根据不同环境进行判断。

preload: process.env.WEBPACK_DEV_SERVER_URL ? path.join(__dirname, 'bundled', 'preload.js') : path.join(__dirname, 'preload.js')

新建src\components\TitleBar.vue组件,标题栏样式和调用preload.js中的方法。

<template>
  <div class="title-bar">
    <div class="title-bar__left">
      <img class="title-bar__logo" src="../assets/logo.png" />
      <div class="title-bar__title">Vue 桌面程序</div>
    </div>
    <div class="title-bar__right" :style="{ '-webkit-app-region': 'no-drag' }">
      <div class="title-bar__icon" @click="minimize">
        <i class="iconfont icon-window-min_line"></i>
      </div>
      <div class="title-bar__icon" @click="windowization" v-show="isMaximizable">
        <i class="iconfont icon-window-window_line"></i>
      </div>
      <div class="title-bar__icon" @click="maximize" v-show="!isMaximizable">
        <i class="iconfont icon-window-max_line"></i>
      </div>
      <div class="title-bar__icon" @click="quit">
        <i class="iconfont icon-delete_line"></i>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  created() {
    this.onIsMaximizable();
  },
  data() {
    return {
      isMaximizable: false,
    };
  },
  methods: {
    minimize() {
      console.log("最小化");
      window.electronAPI.minimize();
    },
    windowization() {
      console.log("窗口化");
      window.electronAPI.windowization();
    },
    maximize() {
      console.log("最大化");
      window.electronAPI.maximize();
    },
    quit() {
      console.log("退出");
      window.electronAPI.quit();
    },
    onIsMaximizable() {
      window.electronAPI.onIsMaximizable((event, isMaximizable) => {
        console.log("监听窗口的变化", isMaximizable);
        this.isMaximizable = isMaximizable;
      });
    },
  },
};
</script>

<style lang="scss" scoped>
@import url("../assets/css/iconfont.css");

.title-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #ddd;
  height: 30px;
  -webkit-app-region: drag;
  .title-bar__logo {
    width: 25px;
    height: 25px;
    margin-left: 10px;
  }
  .title-bar__title {
    margin-left: 6px;
  }
  .title-bar__right {
    margin-right: 10px;
  }
  .title-bar__icon {
    margin-left: 10px;
  }
  .title-bar__left,
  .title-bar__right {
    display: flex;
    align-items: center;
  }
  .title-bar__icon {
    display: flex;
    :active {
      background-color: #999;
    }
  }
}
</style>

src\App.vue页面中引用。

需要调整好样式不然滚动条就…🏊‍

<template>
  <div id="app">
    <title-bar></title-bar>
    <div class="app-body">
      <div id="nav">
        <router-link to="/">Home</router-link> |
        <router-link to="/about">About</router-link>
      </div>
      <router-view />
    </div>
  </div>
</template>
<script>
import TitleBar from "./components/TitleBar.vue";
export default {
  components: { TitleBar },
};
</script>
<style lang="scss">
body {
  margin: 0;
  overflow: hidden;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  overflow: hidden;
  height: 100vh;
}
.app-body {
  overflow: auto;
  height: 100%;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

注意:修改完后记得先执行yarn run electron:build,直接执行yarn run electron:serve,对应的preload.js可能会是旧的文件。

隐藏菜单栏

修改src\background.js文件

import { Menu } from "electron";

// 禁用菜单栏
Menu.setApplicationMenu(null);

隐藏标题栏

修改src\background.js文件

import { BrowserWindow } from "electron";

async function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    // 框架隐藏
    frame: false,
    webPreferences: {
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
    }
  })

  // 略
}

设置拖动窗体

修改src\App.vue文件

-webkit-app-region: drag 用于设定该部分为可拖动区域
-webkit-app-region: no-drag 用于设定该部分为不可拖动区域

<div id="app" style="-webkit-app-region: drag"></div>

相关文档

https://www.electronjs.org/zh/docs/latest/tutorial/context-isolation

源码

可能会有点乱,大多重点代码都在文章里了。

https://github.com/linyisonger/Vue.Examples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux权限的理解

文章目录&#x1f3aa; Linux权限的理解&#x1f680;1.shell命令及其运行原理&#x1f680;2.Linux权限概念⭐2.1 用户与root身份切换⭐2.2 用户与用户身份切换⭐2.3 单条指令提权&#x1f680;3.Linux文件权限⭐3.1 文件属性(第一个字符)⭐3.2 文件角色划分与文件属性⭐3.3 文…

线性代数第四章 向量组的线性相关性

向量组及其线性组合一.向量、向量组1.向量n个有次序的数a1,a2,...,an所组成的数组称为n维向量&#xff0c;这n个数称为该向量的n个分量&#xff0c;第i个数ai称为第i个分量n维向量可以写成一行&#xff0c;也可以写成一列&#xff0c;在没有指明是行向量还是列向量时&#xff0…

Authing 入选长城战略咨询《2022中国潜在独角兽企业研究报告》

12 月 23 日&#xff0c;长城战略咨询&#xff08;GEI&#xff09;发布《2022 中国潜在独角兽企业研究报告》&#xff08;下称《报告》&#xff09;。作为身份云行业领先的代表企业&#xff0c; Authing 凭借着过硬的技术实力和突出的创新能力&#xff0c;首次入选中国潜在独角…

软件测试工程师为什么要写测试用例?

软件测试工程师为什么要写测试用例&#xff1f;相信从事软件测试行业的从业者来讲&#xff0c;测试用例并不陌生。因为测试用例不仅仅是一组简单的文档&#xff0c;它包含前提条件、输入、执行条件和预期结果等等重要内容&#xff0c;并且能够完成一定的测试目的和需求。下面本…

深度学习(20)—— ConvNext 使用

深度学习&#xff08;20&#xff09;—— ConvNext 使用 本篇主要使用convnext做分类任务&#xff0c;其中使用convnext-tiny&#xff0c;其主要有5块 stage0stage1stage2stage3head 文章目录深度学习&#xff08;20&#xff09;—— ConvNext 使用Part 1 ModelPart 2 Traini…

【数据结构】一篇博客带你实现双向带头循环链表!!!(零基础小白也可以看懂)

目录 0.前言 1. 简述双向带头链表 2.双向带头循环链表的实现 2.1 设计双向带头循环链表结构体 2.2双向带头循环链表的初始化 2.3双向带头循环链表的尾插 2.4双向带头循环链表的尾删 2.5双向带头循环链表的头插 2.6双向带头循环链表的头删 2.7双向带头循环链表的插入 …

【面试题】notify() 和 notifyAll()方法的使用和区别

【面试题】notify() 和 notifyAll()方法的使用和区别 Java中notify和notifyAll的区别 何时在Java中使用notify和notifyAll&#xff1f; 【问】为什么wait()一定要放在循环中&#xff1f; Java中通知和notifyAll方法的示例 Java中通知和notify方法的示例 Java中notify和no…

22年我在CSDN做到了名利兼收

写在前面 hi朋友&#xff0c;我是几何心凉&#xff0c;感谢你能够点开这篇文章&#xff0c;看到这里我觉得我们是有缘分的&#xff0c;因着这份缘分&#xff0c;我希望你能够看完我的分享&#xff0c;因为下面的分享就是要汇报给你听的&#xff0c;这篇文章是在 2022 年 12 月 …

从0到1完成一个Vue后台管理项目(二十三、初代项目完成、已开源)

开源地址 项目地址 项目还在优化&#xff0c;会增加很多新功能&#xff0c;UI也会重新设计&#xff0c;已经在修改啦&#xff01; 最近打算加一些组件、顺便分享一些好用的开源项目 现在正在做迁移到vue3TS的版本、预计年后会完事&#xff0c;然后迁移到vite、遇到的问题和报…

docker安装prometheus和grafana

docker安装prometheus和grafana docker安装prometheus和grafana 概念简述安装prometheus 第一步&#xff1a;确保安装有docker第二步&#xff1a;拉取镜像第三步&#xff1a;准备相关挂载目录及文件第四步&#xff1a;启动容器第五步&#xff1a;访问测试 安装grafana 第一步&…

分享66个ASP源码,总有一款适合您

ASP源码 分享66个ASP源码&#xff0c;总有一款适合您 66个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1Jf78pfAPaFo6QhHWWHEq0A?pwdwvtg 提取码&#xff1a;wvtg 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&…

Docker容器与镜像命令

文章目录帮助命令镜像命令容器命令其它命令命令总结帮助命令 显示 Docker 版本信息 docker version显示 Docker 系统信息&#xff0c;包括镜像和容器数 docker info 帮助 docker --help 镜像命令 列出本地主机上的镜像 docker images运行结果 REPOSITORY TAG …

Python采集彼岸4K高清壁纸

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 环境使用: Python 3.8 解释器 Pycharm 编辑器 模块 import re import requests >>> pip install requests ( 更多资料、教程、文档点击此处跳转跳转文末名片加入君羊&#xff0c;找…

【Leetcode面试常见题目题解】5. 最长公共前缀

题目描述 本文是LC第14题&#xff0c;最长公共前缀&#xff0c;题目描述如下&#xff1a; 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 限制 1 < strs.length < 200 0 < strs[i].length < 200 strs[i] 仅…

数据库 MySQL-window安装和卸载

安装 官网&#xff1a; MySQL :: Download MySQL Community Server 或 MySQL :: Download MySQL Community Server (Archived Versions) 文件目录简述 bin存放了可执行文件&#xff0c;docs是文档&#xff0c;include放的是c语言相关的.h文件&#xff0c;lib是c语言的库文件…

wmv是什么格式?如何录制wmv格式的视频?图文教学

很多小伙伴在使用文件的时候&#xff0c;经常会发现自己的一些文件后缀名是wmv。或者说在工作、学习的过程中&#xff0c;有过被要求使用wmv格式的文件。wmv是什么格式&#xff1f;如何录制wmv格式的视频&#xff1f;今天小编就来详细的跟大家说说。 一、wmv是什么格式&#xf…

SpringBoot复习(一)

底层注解 Configuration 自定义配置类 Bean: 可以通过Bean注解将方法的返回值交给ioc容器来管理 组件id为方法名&#xff0c;组件的类型就是方法的返回类型。 默认组件是单例的 Configuration: 告诉springboot这是一个配置类之前的配置文件 配置类本身也是组件&#xff0c;由s…

【Linux】Makefile/make - 快速理解入门

目录 一、概念理解 1、基本概念 2、举例说明 二、编写 Makefile 1、依赖关系和依赖方法 2、文件清理 3、扩展内容 一、概念理解 1、基本概念 在我们学习 Linux 的过程中&#xff0c;我们可以直接使用 gcc 指令对程序的文本文件逐个进行编译处理&#xff0c;这是因为我…

ASP.NET Core 3.1系列(26)——Autofac中的实例生命周期

1、前言 前面的博客主要介绍了Autofac中的一些注册方法&#xff0c;下面就来介绍一下Autofac中实例的生命周期。之前在介绍ASP.NET Core内置IoC容器的时候说过&#xff0c;实例的生命周期有&#xff1a;瞬时生命周期、域生命周期、全局单例生命周期&#xff0c;而Autofac在这三…

mysql-8.0.31-winx64详细安装教程

一、下载MySQL MySQL官网&#xff1a;https://www.mysql.com/cn/ mysql-8.0.31-winx64下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 2、下载结束后&#xff0c;解压到指定目录&#xff0c;笔者存放在D盘 &#xff0c;为求简单&#xff0c;设置目录如下&#…