Vue3+Pinia实现持久化动态主题切换

PC端主题切换大家都用过,下面用Vue3+Pinia实现一下这个过程;
【源码地址】

在这里插入图片描述

1、准备工作

npm install pinia
npm install pinia-plugin-persist

image.png

2、基础配置

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import bootstrap from "../bootstrap";
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist';const app = createApp(App);
const store = createPinia()
store.use(piniaPluginPersist);app.use(store);
// APP.vue
<template><div><a-config-provider :locale="locale" :theme="{ token: { colorPrimary: themeState.themes && themeState.currTheme ? themeState.themes[themeState.currTheme].themeColor1 : '#4A51FF', } }" ><RouterView/></a-config-provider></div>
</template><script setup>
import {ref, reactive, provide, onMounted, onBeforeUnmount } from 'vue'
import {useRouter} from "vue-router";
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import { themeStore } from '@/stores/theme';dayjs.locale('zh-cn');// 国际化配置-默认中文
const locale = ref(zhCN);
const $router = useRouter();
const themeState = themeStore();let timer = reactive(null)onMounted(() => {// 初始化主题色themeState.getTheme && themeState.getTheme('themeColor');
});</script>

3、Stores 部分

// src/stores/index.js
import { createPinia, } from 'pinia';const pinia = createPinia()export default pinia;
// src/stores/theme.js
import { defineStore } from 'pinia'
import {setStorage, getStorage} from "@/utils/util";export const themeStore = defineStore('theme',{state: () => {return {currTheme: "默认", // 当前主题themes: {"默认": {themeColor1: '#4A51FF',themeColor2: '#4A51FF',themeColor7: '#4A51FF', //textColor1: '#181818',textColor2: '#555555',},"海盐蓝": {themeColor1: '#4691C8',themeColor2: '#4691C8',themeColor7: '#4691C8', //textColor1: '#181818',textColor2: '#555555',},"翠竹绿": {themeColor1: '#347B45',themeColor2: '#347B45',themeColor7: '#347B45', //textColor1: '#181818',textColor2: '#555555',},"魅力紫": {themeColor1: '#6837C9',themeColor2: '#6837C9',themeColor7: '#6837C9', //textColor1: '#181818',textColor2: '#555555',},}}},persist: {enabled: true,// 自定义持久化参数strategies: [{// 自定义keykey: 'theme',// 自定义存储方式,默认sessionStoragestorage: localStorage, // localStorage,// 指定要持久化的数据,默认所有 state 都会进行缓存,可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。paths: ['currTheme', 'themes']}]},// 相当于计算属性(有数据缓存)getters: {getThemes(state){return state.themes},},// actions即可以是同步函数也可以是异步函数actions: {// 切换主题changeStyle (obj) {for (let key in obj) {document.getElementsByTagName("body")[0].style.setProperty(`--${key}`, obj[key]);}},setThemeColor (themeName){let { showLock, currTheme, sideCollapsed, themes } = this;let theme = { showLock, currTheme, sideCollapsed, themes }setStorage("theme", JSON.stringify(theme));const themeConfig = this.getThemes[themeName];let themeInfo = {};if(getStorage("theme")) {themeInfo = JSON.parse(getStorage("theme"));}// 如果有主题名称,那么则采用我们定义的主题if (themeConfig) { // 保存主题色到本地this.changeStyle(themeConfig); // 改变样式} else {this.changeStyle(themeInfo.themes); // 改变样式}},setTheme ( theme, type ){if (type === 'themeColor') {this.setThemeColor(theme);} else if (type === 'FontFamily') {this.setFontFamily(theme);}},getTheme (type){let { currTheme } = this;if (type === 'themeColor') {if(getStorage("theme")) {let themeInfo = JSON.parse(getStorage("theme"));this.setThemeColor(themeInfo.currTheme);} else {this.setThemeColor(currTheme);}} else if (type === 'FontFamily') {let FontFamily = getStorage("FontFamily");this.setFontFamily(FontFamily);}},}
});

4、页面使用

// header.vue
<template><div class="headerCompView"><div class="header-left"><slot name="left"></slot></div><div class="header-right"><div class="theme-list"><a-popover placement="bottom" trigger="click" overlayClassName="themeUserPop" :overlayInnerStyle="{width: '230px'}"><template #content><div class="theme-item" v-for="(item, index) in themeOptions" :key="index" @click="onPressTheme(item.name)":style="{color: item.name === currentThemeName ? '#4A51FF' : ''}" ><div class="item-left"><a-tag :color="item.data.themeColor1" style="height: 20px; width: 20px;"></a-tag><span class="title"> {{item.name}} </span></div><div class="item-right"><CheckOutlined v-if="item.name === currentThemeName" :style="{color: item.data.themeColor1 ? item.data.themeColor1 : ''}"/></div></div></template><div class="theme-options"><BgColorsOutlined /><span style="margin-left: 10px;">切换主题</span></div></a-popover></div></div></div>
</template><script setup>
import { ref, onMounted } from 'vue';
import {themeStore} from "@/stores/theme"const $router = useRouter();
const themeState = themeStore(); let themeOptions = ref([]);
let currentThemeName = ref("默认");onMounted(() => {collapsed.value = props.collapsedStatus;initTheme();
});// 初始化主题
const initTheme = () => {let arr = [];for (let index in themeState.themes) {let item = {name: index,data: themeState.themes[index],}arr.push(item)}themeOptions.value = arr;currentThemeName.value = localStorage.getItem('themeName');
}// 设置主题
const onPressTheme = (e) =>{themeState.currTheme = e;// console.log("themeState.currTheme", themeState.currTheme);themeState.setTheme(e, 'themeColor');currentThemeName.value = e;
};</script><style lang="less" scoped>
@import (reference) "@/utils/common";.themeUserPop{.theme-item{height: 40px;cursor: pointer;display: flex;justify-content: space-between;align-items: center;font-weight: 500;line-height: 16px;border-bottom: 1px dashed #EFF1F5;.item-left{.flexCenter;.title{font-size: 14px;vertical-align: middle;line-height: 20px;}}}.theme-item:hover{color: #4A51FF;}
}
</style>
// src/utils/common.less```
@theme: var(--themeColor1);
// 默认的主题颜色
@themeColor1: var(--themeColor1);
@themeColor2: var(--themeColor2);
@themeColor3: var(--themeColor3);
@themeColor4: var(--themeColor4);
@themeColor5: var(--themeColor5);
@themeColor6: var(--themeColor6);
@themeColor7: var(--themeColor7);
@textColor1: var(--textColor1);
@textColor2: var(--textColor2);
```

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

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

相关文章

红日靶场 4

靶场配置 ​ 733 x 668899 x 819 ​ ​ 733 x 6161466 x 1232 ​ ​ 733 x 6261449 x 1237 ​ ​ 733 x 6301450 x 1247 ​ IP 地址分配&#xff1a; Win7: 192.168.183.133(内网)Ubuntu: 192.168.183.134(内网) 192.168.120.137(外网)DC: 192.168.183.130(内网)Kali…

Python综合数据分析_根据订单求RFM值

文章目录 0.导入数据1.数据可视化2.数据清洗3.特征工程4.构建User用户表5.求R值6.求F值7.求M值 0.导入数据 import pandas as pd #导入Pandas df_sales pd.read_csv(订单.csv) #载入数据 df_sales.head() #显示头几行数据 1.数据可视化 import matplotlib.pyplot as plt #导…

js逆向第13例:猿人学第6题js混淆-回溯赛

文章目录 m是加密字符串怎么来的?浏览器环境检测本地运行的js代码任务六:采集全部5页的彩票数据,计算全部中奖的总金额(包含一、二、三等奖) 此题总体难度低于第5题,老规矩还是查看控制台请求地址https://match.yuanrenxue.cn/api/match/6?m=rPRDgpbV3Wd%252FyPfURQAkxK…

使用Vite创建vue3工程

介绍 使用Vite构建工具&#xff0c;创建Vue3工程 示例 第一步&#xff1a;执行创建项目的命令&#xff0c;study-front-vue3是项目名称 npm init vite-app study-front-vue3第二步&#xff1a;进入项目文件夹&#xff0c;执行命令&#xff0c;安装模块 cd study-front-vue…

使用qtquick调用python程序,pytorch

一. 内容简介 使用qtquick调用python程序 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3pytorch 安装pytorch(http://t.csdnimg.cn/GVP23) 2.4QT 5.14.1 新版QT6.4,&#xff0c;6.5在线安装经常失败&#xff0c;而5.9版本又无法编译64位程序&#xf…

程序员为什么不能一次把功能写好,是因为他不想吗

引言 交流一下为什么他做的功能这么多Bug 大家好&#xff0c;最近看到一个有趣的问题&#xff1a; 程序员为什么要不能一次性写好&#xff0c;需要一直改Bug&#xff1f; 在我看来&#xff0c;程序员也是人&#xff0c;并非机器。 拿这个问题去质问程序员&#xff0c;答案无…

Java学习,一文掌握Java之SpringBoot框架学习文集(3)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【网络】网络层协议ARP和IP协议转发流程

目录 一、IP概述 1.1 IP简介 1.2 IP协议 二、IP地址与硬件地址 三、地址解析协议ARP 3.1 ARP协议简介 3.2 ARP工作流程 3.3 ARP的四种典型情况 四、IP协议的转发流 一、IP概述 1.1 IP简介 IP地址&#xff08;Internet Protocol Address&#xff09;是指互联网协议地址…

[VUE]1-创建vue工程

目录 基于脚手架创建前端工程 1、环境要求 2、操作过程 3、工程结构 4、启动前端服务 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数据结构和算法&#xff0c…

如何写html邮件 —— 参考主流outook、gmail、qq邮箱渲染邮件过程

文章目录 ⭐前言⭐outlook渲染邮件⭐gmail邮箱渲染邮件⭐qq邮箱渲染邮件 ⭐编写html邮件&#x1f496;table表格的属性&#x1f496;文本&#x1f496;图片&#x1f496;按钮&#x1f496;背景图片 ⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于 …

云卷云舒:【实战篇】对象存储迁移

云卷云舒&#xff1a;【实战篇】MySQL迁移-CSDN博客 1. 简介 对象存储与块存储、文件存储并列为云计算三大存储模型。提供海量存储空间服务&#xff0c;具备快速的数据存取性能、高可靠和数据安全性&#xff0c;通过标准的RESTful API接口和丰富的SDK包来提供服务&#xff0c…

3D模型UV展开原理

今年早些时候&#xff0c;我为 MAKE 杂志写了一篇教程&#xff0c;介绍如何制作视频游戏角色的毛绒动物。 该技术采用给定的角色 3D 模型及其纹理&#xff0c;并以编程方式生成缝纫图案。 虽然我已经编写了一般摘要并将源代码上传到 GitHub&#xff0c;但我在这里编写了对使这一…

Presto CLI学习

1. 序言 作为Presto的客户端之一&#xff0c;Presto CLI是一个基于终端的交互式shell&#xff0c;对应presto源码中的presto-cli模块 Presto CLI的本质是一个self-executing jar —— presto-cli-version-executable.jar&#xff0c;就像一个普通的UNIX可执行文件 因此&#…

olap/spark-tungsten:codegen

15721这一章没什么好说的&#xff0c;不再贴课程内容了。codegen和simd在工业界一般只会选一种实现。比如phothon之前用codegen&#xff0c;然后改成了向量化引擎。一般gen的都是weld IR/LLVM IR/当前语言&#xff0c;gen成C的也要检查是不是有本地预编译版本&#xff0c;要不没…

城市建设模拟游戏:鼠托邦 RATOPIA 中文免安装版

《鼠托邦》是一款由独立游戏开发团队Cassel Games开发的基地建设模拟游戏。在游戏中&#xff0c;玩家需要管理一个庞大的地下鼠国&#xff0c;打造理想中的“鼠托邦”。玩家可以化身为糖果派对游戏中的老鼠女王&#xff0c;带领老鼠民众建设城市、勘探地下领域以扩展生存空间。…

Web前端-JavaScript(ES6)

文章目录 1.ES5数组新方法1.1 数组方法forEach遍历数组1.2 数组方法filter过滤数组1.3 数组方法some1.4 some和forEach和filter的区别1.5 find()1.6 findIndex()1.7 trim去除字符串两端的空格1.8 获取对象的属性名1.9 Object.defineProperty 2.ES6语法2.1 ES6概述2.2 为什么使用…

CTF数据分析题详解

目录 题目一(1.pcap) 题目二(2.pcap) 题目三(3.pcap) 题目四(4.pcap) CTF流量分析经典例题详解-CSDN博客 本文章涉及的所有题目附件下载地址&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/18mWo5vn1zp_XbmcQrMOKRA 提取码&#xff1a;hrc4 声明&#xff1a;这里…

WorkPlus AI助理为企业提供智能客服的机器人解决方案

在数字化时代&#xff0c;企业面临着客户服务的重要挑战。AI客服机器人成为了提升客户体验和提高工作效率的关键工具。作为一款优秀的AI助理&#xff0c;WorkPlus AI助理以其智能化的特点和卓越的功能&#xff0c;为企业提供了全新的客服机器人解决方案。 为什么选择WorkPlus A…

Python机器学习入门必学必会:机器学习与Python基础

1.机器学习常见的基础概念 根据输入数据是否具有“响应变量”信息&#xff0c;机器学习被分为“监督式学习”和“非监督式学习”。“监督式学习”即输入数据中即有X变量&#xff0c;也有y变量&#xff0c;特色在于使用“特征&#xff08;X变量&#xff09;”来预测“响应变量&…

【Python从入门到进阶】46、58同城Scrapy项目案例介绍

接上篇《45、Scrapy框架核心组件介绍》 上一篇我们学习了Scrapy框架的核心组件的使用。本篇我们进入实战第一篇&#xff0c;以58同城的Scrapy项目案例&#xff0c;结合实际再次巩固一下项目结构以及代码逻辑的用法。 一、案例网站介绍 58同城是一个生活服务类平台&#xff0c…