Electron 实现切换暗_亮模式与主题

news2024/11/25 23:03:17

QQ20230105-180050-HD.gif

文章末尾附上仓库地址!!!!

清单

  • 模板基于 electron-vite-vue vue3 + ts + vite
  • 组件库 element-plus
  • hooks库 vueuse 、useElementPlusTheme

初始化工程

使用 electron-vite 作为模板,方便大家尽快吧项目跑起来

# 创建模板
npm create electron-vite
# 进入目录
cd electron-vite-vue

# 下载依赖,如果有异常的话可以尝试 cnpm 
cnpm i

# 目前这个模板缺少了 esbuild 依赖,所以需要补上
cnpm i esbuild -D 

# 启动项目
npm run dev

出现这个页面,初始化工程部分就结束了

image.png

ElementPlus 引入

cnpm i element-plus

main.ts 全局引入 ElementPlus

修改 src/main.ts

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
// ElementPlus 引入
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";

const app = createApp(App);
// ElementPlus 注册
app.use(ElementPlus);
app.mount("#app").$nextTick(() => {
  postMessage({ payload: "removeLoading" }, "*");
});

启动项目如果报以上错误的话,将缺的两个包下载就好了
image.png

cnpm i @vue/shared @vue/reactivity

测试组件引用

修改 src/App.vue 测试一下组件引用, 务必清空src/style.css哈

<template>
  <el-container>
    <el-header class="header">Header</el-header>
    <el-container>
      <el-aside width="200px" class="aside">Aside</el-aside>
      <el-container>
        <el-main class="main">Main</el-main>
        <el-footer class="footer">Footer</el-footer>
      </el-container>
    </el-container>
  </el-container>
  <el-row class="mb-4">
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>
  <el-row>
    <el-col :sm="12" :lg="6">
      <el-result
        icon="success"
        title="Success Tip"
        sub-title="Please follow the instructions"
        >
        <template #extra>
          <el-button type="primary">Back</el-button>
        </template>
        </el-result>
          </el-col>
          <el-col :sm="12" :lg="6">
          <el-result
          icon="warning"
          title="Warning Tip"
          sub-title="Please follow the instructions"
            >
            <template #extra>
            <el-button type="primary">Back</el-button>
            </template>
            </el-result>
            </el-col>
            <el-col :sm="12" :lg="6">
            <el-result
          icon="error"
          title="Error Tip"
          sub-title="Please follow the instructions"
            >
            <template #extra>
            <el-button type="primary">Back</el-button>
            </template>
            </el-result>
            </el-col>
            <el-col :sm="12" :lg="6">
            <el-result icon="info" title="Info Tip">
            <template #sub-title>
            <p>Using slot as subtitle</p>
            </template>
            <template #extra>
            <el-button type="primary">Back</el-button>
            </template>
            </el-result>
            </el-col>
            </el-row>
            </template>

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

<style>
  .header {
    background: var(--el-color-primary);
  }
  .aside {
    background: var(--el-bg-color-page);
  }
  .main {
    background: var(--el-bg-color);
  }
  .footer {
    background: var(--el-bg-color-page);
  }
</style>

image.png

ElementPlus暗黑模式

官方文档传送门

  • ElementPlus的暗黑模式 切换方式是在 html元素属性上 增删 class=“dark”
  • 暗黑模式需要在man.ts 文件引入
  • 可以通过 useDark | VueUse 切换暗黑模式

引用element-plus暗黑主题样式

修改 src/main.ts

//.......
// 增加暗黑模式样式文件
import 'element-plus/theme-chalk/dark/css-vars.css'
//.......

使用useColorMode

官方文档传送门

具有自动数据持久化的主题模式hooks(深色/浅色/自定义)。

  • 将颜色模式存在本地存储中持久化
  • 颜色模式为相应式属性
cnpm i @vueuse/core

修改 src/App.vue 改造增加模式切换部分

<template>
  <div style="margin-top: 20px">
    <el-radio-group v-model="mode" size="small">
      <el-radio-button label="light">浅色</el-radio-button>
      <el-radio-button label="dark">暗黑</el-radio-button>
      <el-radio-button label="auto">跟随系统</el-radio-button>
    </el-radio-group>
  </div>
<!--   ......... -->
</template>
<script setup lang="ts">
import { useColorMode } from "@vueuse/core";
import { onBeforeMount } from "vue";
const mode = useColorMode({
  // 如果模式为auto也需要回显回auto
  emitAuto: true,
  // 默认模式先默认auto,后续通过Electorn拿到当前App主题
  initialValue: "auto",
});
</script>

QQ20230105-162711-HD.gif

Electron暗黑主题同步

细心的小伙伴可能发现了,在改变暗黑模式时,顶部的窗口颜色并没有同步,只有在auto模式下才同步。这是因为顶部的窗口是原生窗口,我们只是改变了webpage 也就是我们特指“html” 部分的主题颜色,下面我们就像两部分联动起来。

IPC(进程间通信)

  • ipcMain模块用于从主进程(main process)异步通信到renderer进程。
  • ipcRenderer模块用于从一个renderer进程异步传送到主进程。

这里本章不做过多介绍,可以先简单理解为发布订阅,后续会更新此系列文章。

改造主线程

修改 electron/main/index.ts 增加两个主线程监听,放在文件末尾即可

// 获取APP当前主题模式
ipcMain.handle("dark-mode", () => {
  return nativeTheme.themeSource;
});
// 设置APP主题模式
ipcMain.handle("dark-mode:change", (_, type: "system" | "light" | "dark") => {
  nativeTheme.themeSource = type;
  return nativeTheme.themeSource;
});

改造

修改 src/App.vue 页面挂载时获取APP 的主题,同步到主题中

<script setup lang="ts">
  import { useColorMode } from "@vueuse/core";
  import { ipcRenderer } from "electron";
  import { onBeforeMount } from "vue";
  const mode = useColorMode({
    emitAuto: true,
    initialValue: "auto",
  });
  // 监听 Mode 改变
  const changeModel = (mode: "light" | "dark" | "auto") => {
    // Electorn的主题模式 auto 为 system 所以需要转换
    ipcRenderer.invoke("dark-mode:change", mode === "auto" ? "system" : mode);
  };
  onBeforeMount(() => {
    // 通过 ipcRenderer 与主线程通信
    // 获取到App主题 同步到 useColorMode 中
    ipcRenderer.invoke("dark-mode").then((type: "light" | "dark" | "system") => {
      mode.value = type == "system" ? "auto" : type;
    });
  });
</script>

QQ20230105-172532-HD.gif

主题切换

因为 ElementPlus 的主题可以通过css变量控制,如下面这个图一样。
image.png

useElementPlusTheme

useElementPlusTheme仓库地址

这个hooks没有找到原作者的博客地址以及文档,但是找到了仓库地址。为了代码可控性以及维护性,直接在文件中创建useElementPlusTheme 而不是下载。

增加文件 src/hooks/useElementPlusTheme.ts

import { onBeforeMount } from "vue";

/** 变量前缀 */
const PRE = "--el-color-primary";
const PRE_LIGHT = `${PRE}-light`;
const PRE_DARK = `${PRE}-dark`;
/** 白色 */
const WHITE = "#ffffff";
/** 黑色 */
const BLACK = "#000000";

const html = document.documentElement;

/**
 * 混合颜色
 */
const mix = (color1: string, color2: string, weight: number) => {
  weight = Math.max(Math.min(Number(weight), 1), 0);
  const r1 = parseInt(color1.substring(1, 3), 16);
  const g1 = parseInt(color1.substring(3, 5), 16);
  const b1 = parseInt(color1.substring(5, 7), 16);
  const r2 = parseInt(color2.substring(1, 3), 16);
  const g2 = parseInt(color2.substring(3, 5), 16);
  const b2 = parseInt(color2.substring(5, 7), 16);
  const r = Math.round(r1 * (1 - weight) + r2 * weight);
  const g = Math.round(g1 * (1 - weight) + g2 * weight);
  const b = Math.round(b1 * (1 - weight) + b2 * weight);
  const _r = ("0" + (r || 0).toString(16)).slice(-2);
  const _g = ("0" + (g || 0).toString(16)).slice(-2);
  const _b = ("0" + (b || 0).toString(16)).slice(-2);
  return "#" + _r + _g + _b;
};

/**
 * 更换颜色的方法
 * @param color 颜色
 */
const changeTheme = (color?: string) => {
  if (!color) return;
  // 设置主要颜色
  html.style.setProperty(PRE, color);
  // 循环设置次级颜色
  for (let i = 1; i < 10; i += 1) {
    html.style.setProperty(`${PRE_LIGHT}-${i}`, mix(color, WHITE, i * 0.1));
  }
  // 设置主要暗色
  const dark = mix(color, BLACK, 0.2);
  html.style.setProperty(`${PRE_DARK}-2`, dark);
};

export function useElementPlusTheme(color?: string) {
  onBeforeMount(() => changeTheme(color));
  return {
    changeTheme,
  };
}

使用 useElementPlusTheme

修改 src/App.vue

<template>
<!--  ......  -->
  <div>主题颜色: <el-color-picker v-model="themeColor" @change="changeTheme"/></div>
<!--  ......  -->
</template>
<script setup lang="ts">
import { useElementPlusTheme } from "./hooks/useElementPlusTheme";
// ......
const themeColor = ref("#cc312c");
const { changeTheme } = useElementPlusTheme(themeColor.value);
</script>

QQ20230105-175803-HD.gif

GitHub仓库地址

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

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

相关文章

Java面试之数据库篇

一、基础 1.数据库事务的特征ACID 原子性&#xff08;Atomicity&#xff09;&#xff1a;原子性是指事务包含的所有操作要么全部成功&#xff0c;要么全部失败回滚&#xff0c;这和前面两篇博客介绍事务的功能是一样的概念&#xff0c;因此事务的操作如果成功就必须要完全应用…

UOS服务器操作系统多版本Java切换

一、修改java的环境变量和软链接来实现版本切换 1、配置环境变量 sudo vim &#xff5e;/.bashrc 2、创建java运行程序软连接 3、使配置生效&#xff0c;并检查java版本 source /etc/profile 二、使用update-alternatives 进行版本的切换 1、同时安装了openjdk-8-jdk 和…

shell第七天作业——awk

题目 1、获取根分区剩余大小 2、获取当前机器ip地址 3、统计出apache的/var/log/httpd/access_log文件中访问量最多的前3个IP 4、打印/etc/passwd中UID大于500的用户名和uid 5、/etc/passwd 中匹配包含root或sys或tcp的任意行 6、请打印出/etc/passwd 第一个域&#xff0…

指针进阶之数组参数和指针参数

文章目录一、回顾1.字符指针2.指针数组和数组指针&#xff08;1&#xff09;指针数组&#xff08;2&#xff09;数组指针二、数组参数1.一维数组传参&#xff08;1&#xff09;整型数组&#xff08;2&#xff09;指针数组&#xff08;3&#xff09;总结2.二维数组传参&#xff…

基于Python tensorflow2.3实现的水果识别系统源码+模型+数据集,卷积神经网络的入门案例

水果识别-基于tensorflow2.3实现 水果识别是卷积神经网络的入门案例&#xff0c;这里我将模型的训练、测试、保存以及使用整合在了一起&#xff0c;至于原理部分&#xff0c;大家可以参考知乎或者B站上的回答&#xff0c;在这里我就不赘述了 完整代码下载地址&#xff1a;基于…

计算机网络实验---验证性实验

实验一/ipconfig 实作一 实作二 实验二/ping 实作一 实作二 实验三/tracert 实作一 实作二 实验四/ARP 实作一 实作二 实作二 实验五/DHCP 实作一 实验六/netstat 实作一 实作二 实验七/DNS 实作一 实作二 实作二 实验八/cache 实作一 实作二 总结 实验一/ipconfig 实…

[Leetcode] 二叉树的遍历

转载自&#xff08;有删减和少量改动&#xff09; 图解二叉树的四种遍历 https://leetcode.cn/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/1. 相关题目144.二叉树的前序遍历 https://leetcode.cn/problems/binary-tree-p…

【SpringMVC 入门教程】

SpringMVC_day02 &#x1f308;博客主页&#xff1a;屠一乐的博客 &#x1f4c5; 发文时间&#xff1a;2023.1.5 &#x1f388; 一定存在只有你才能做成的事 &#x1f339; 博主水平有限&#xff0c;如有错误&#xff0c;欢迎指正 欢迎各位&#x1f44d;收藏&#x1f48e;评论✉…

MacBookPro安装mysql遇到的几个问题

用Mac的好处是不用开关机&#xff0c;无弹窗无广告&#xff0c;坏处是在安装某些第三方的软件时&#xff0c;总是和视频教程上的winows版不一致&#xff0c;需要自己上网找资料尝试怎么安装。今天学python&#xff0c;需要安装mysql&#xff0c;幸好网上有一些文章&#xff0c;…

Vulnhub靶机:MISDIRECTION_ 1

目录介绍信息收集主机发现主机信息探测网站探测反弹shell方式1&#xff1a;使用nc方式2&#xff1a;使用bash方式3&#xff1a;使用MSF提权sudo提权passwd提权docker提权参考介绍 系列&#xff1a;Misdirection&#xff08;此系列共1台&#xff09; 发布日期&#xff1a;2019 …

【ClickHouse】从Mysql迁移到ClickHouse大全

从关系型的数据库(Mysql)升级到列式管理的联机分析型数据库(ClickHouse)&#xff0c;这不亚于是小米加步枪升级为加特林机关枪的性能提升了&#xff0c;查询能力等确实是大大的提升了&#xff0c;这出现了一个问题我们之前存储在Mysql里的历史数据怎么往ClickHouse里面迁移呢&a…

访问者模式Visitor

1.意图&#xff1a;表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的操作。 2.结构 Visitor&#xff08;访问者&#xff09;为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请…

本地机器 Google Colab 通过 SSH 连接远程服务器

1. 情景描述 我自己笔记本配置太垃圾&#xff0c;想要用学校的深度学习服务器在Colab上跑程序。 2. 环境描述 远程服务器 (Ubuntu)&#xff1a; 用pip安装 jupyter notebook 以及 jupyter_http_over_ws 拓展包 (前提有python环境和pip) pip install notebookpip install j…

Android设计模式详解之外观模式

前言 外观模式也称门面模式&#xff0c;在开发过程中的运用频率非常高&#xff1b; 定义&#xff1a;要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行&#xff1b;门面模式提供一个高层次的接口&#xff0c;使得子系统更易于使用&#xff1b; 使用场景&#…

6.3 Docker

目录 6.3.1 Docker概述 6.3.1.1 什么是Docker 6.3.1.2 Docker组成 6.3.2 Docker的安装 6.3.2.1 下载Docker依赖的环境 6.3.2.2 指定Docker镜像源 6.3.2.3 安装Docker 6.3.2.4 启动Docker并测试 6.3.3 Docker的中央仓库 6.3.4 Docker操作 6.3.4.1 镜像操作 6.3.4.…

从url获取参数并转为对象

const getParameters URL > JSON.parse({"${decodeURI(URL.split("?")[1]).replace(/"/g, \\").replace(/&/g, ",").replace(//g, ":")}"})getParameters("https://www.google.com.hk/search?qjsmd&neww…

【深度学习】李宏毅2021/2022春深度学习课程笔记 - Self-supervised Learning(自监督式学习)

文章目录一、芝麻街与进击的巨人二、Self-supervised Learning三、BERT3.1 Masking Input3.2 Next Sentence Prediction3.3 GLUE 任务集3.4 How to use BERT3.4.1 Case13.4.2 Case23.4.3 Case33.4.4 Case43.5 Training BERT is challenging!3.6 Pre-Training a Seq2Seq Model3.…

ERP是什么意思?

“ERP到底是一个怎么样的存在&#xff1f;为何有那么多的方面&#xff1f;如何学习&#xff1f;” 本文从ERP起源讲起&#xff0c;结合制造业离散制造与流程制造的ERP系统区别&#xff0c;详解ERP概念。 文章有点长&#xff0c;但如果你耐心看完&#xff0c;相信你会对ERP有一…

elasticsearch 基本语法(常见的RESTFUL API)

一 . ES的基本语法 文章目录一 . ES的基本语法1.Query String 语法2.Query DSL 语法3. Full-text queries 全文检索4. Phrase search 短语搜索5.Query and filter 查询和过滤6. Compound queries 查询7.HighLight search(高亮显示)测试数据内容&#xff1a;PUT /product/_doc/1…

科研试剂 Dextran-DBCO;葡聚糖-二苯并环辛烯;生物可降解高分子聚合物

DBCO修饰的葡聚糖聚 Dextran-DBCO 葡聚糖-二苯并环辛烯 名称&#xff1a;DBCO修饰葡聚糖 英文名称&#xff1a;Dextran-DBCO 外观状态&#xff1a;白色粉末 溶剂&#xff1a;DMSO等常规有机溶剂。 性状&#xff1a;基于不同的分子量&#xff0c;呈白色/类白色固体粉末&…