当前位置: 首页 > news >正文

基于 vue3、vite、antdv、css 变量实现在线主题色切换

1、前言

动态切换主题是一个很常见的需求. 实现方案也有很多, 如:

  • 编译多套 css 文件, 然后切换类名(需要预设主题, 不够灵活)

  • less 在线编译(不兼容 ie, 性能较差)

  • css 变量(不兼容 ie)

但是这些基本都是针对 vue2 的, 我在网上并没有找到比较完整的解决 vue3 换肤的方案, 大多只处理了自定义样式或者 ui 框架(比如 antdv)二者之一的主题切换, antdv 官网对动态主题的说明也不够清晰, 且与推荐的按需加载插件 unplugin-vue-components 有冲突

我最终放弃了 unplugin-vue-components 的样式的按需加载, 采取组件按需加载, 样式全量加载, 并通过 css 变量和 antdv 的 ConfigProvider 实现了在线主题色切换

下面是具体是实现

2、基础环境搭建

1、项目创建

根据vite 官方文档, 使用社区模板, 即可轻松创建基于 vue3 和 ts 的项目模板

npm init vite@latest
复制代码

然后按照提示, 依次选择 vuevue-ts , 即可创建 vue3 + ts + vite 项目

2、eslint 和 prettier 配置

安装依赖

yarn add eslint eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier -D
复制代码

添加配置

  1. 新增.eslintrc.json

// .eslintrc.json{"env":{"browser":true,"es2021":true,"node":true,"vue/setup-compiler-macros":true},"extends":["eslint:recommended","plugin:vue/vue3-recommended","plugin:@typescript-eslint/recommended","plugin:prettier/recommended"],"parser":"vue-eslint-parser","parserOptions":{"ecmaVersion":"latest","parser":"@typescript-eslint/parser","sourceType":"module"},"plugins":["vue","@typescript-eslint"],"rules":{"vue/comment-directive":"off","prettier/prettier":"off",// 允许单字单词作为组件名"vue/multi-word-component-names":"off","@typescript-eslint/no-non-null-assertion":"off"}}复制代码
  1. 新增.prettierrc.js

// .prettierrc.jsmodule.exports = {printWidth: 80, //单行长度tabWidth: 2, //缩进长度useTabs: false, //使用空格代替tab缩进semi: true, //句末使用分号singleQuote: true, //使用单引号
};
复制代码
  1. 安装 vscode 插件

安装下列 vscode 插件(已安装可跳过)

  • Vue Language Features (Volar)

  • Prettier - Code formatter

Volar 可以简单理解为是 vue3 的 Vetur, 如果是既有 vue2 项目又有 vue3 项目的, 可在工作区修改设置

新建.vscode 文件夹, 在.vscode 新建 extensions.json 和 settings.json

// .vscode/extensions.json{"recommendations":["johnsoncodehk.volar"]}复制代码
// .vscode/settings.json{"editor.formatOnSave":true,"editor.defaultFormatter":"esbenp.prettier-vscode","editor.codeActionsOnSave":{"source.fixAll":true},"vetur.format.enable":true,"vetur.validation.script":false,"vetur.validation.style":false,"vetur.validation.template":false}复制代码
  1. 配置 lint 相关命令

修改 package.json

// package.json
...
"scripts":{"dev":"vite","build":"vue-tsc --noEmit && vite build","preview":"vite preview","lint":"eslint . --ext .vue,.ts,.jsx,.tsx --fix","format":"prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}"},
...
复制代码

执行 lint 和 format 即可校验和格式化项目文件

3、自定义主题色切换

1、引入 less

这套方案里, less 不是必须的, 使用 css、sass、postCSS 都可以, 其核心原理是使用了 css 变量, 但是项目需要使用 less 的类名嵌套、变量、函数等功能, 且 antd 本身是基于 less 的, 因此项目的样式这里也统一使用 less.

vite 本身是支持 less 等 css 预编译器的, 只需要安装 less, 然后直接在 style 添加属性 lang = 'less' 即可使用 less

yarn add less -D
复制代码

在 HelloWorld.vue 里使用 less

<!-- src/components/HelloWorld.vue -->
<script setup lang="ts">
defineProps<{ msg: string }>();
</script><template><div class="title">{{ msg }}</div>
</template><style lang="less" scoped>
.title {color: red;
}
</style>
复制代码

2、自定义全局 less 变量

在 assets 新建 styles 目录存放样式, 在 styles 下新建 common 目录存放公共样式和变量, 在 common 下新建 common.less、var.css 和 var.less

/* src/assets/styles/common/var.css 存放css变量 */:root {--ant-primary-color: #18a058;
}
复制代码
/* src/assets/styles/common/var.less 存放less变量 */@primary-color:var(--ant-primary-color, #18a058);
复制代码
/* src/assets/styles/common/common.less 存放公共样式 */a {color: @primary-color;
}
复制代码

在 vite.config.ts 引入 var.less, var.less 里定义的 less 变量便可以在全局使用

// vite.config.tsimport { defineConfig } from'vite';
import vue from'@vitejs/plugin-vue';
import path from'path';functionresolve(url: string): string {return path.resolve(__dirname, url);
}// https://vitejs.dev/config/exportdefaultdefineConfig({plugins: [vue()],resolve: {alias: {'@': resolve('./src'),'~@': resolve('./src'),},},css: {preprocessorOptions: {less: {// 全局添加lessadditionalData: `@import '@/assets/styles/common/var.less';`,javascriptEnabled: true,},},},
});
复制代码

此时 ts 并不能识别 nodejs 的模块, path 会报错, 需要安装@types/node

yarn add @types/node -D
复制代码

然后修改 tsconfig.node.json

// tsconfig.node.json{"compilerOptions":{"composite":true,"module":"esnext","moduleResolution":"node","allowSyntheticDefaultImports":true},"include":["vite.config.ts"]}复制代码

在 App.vue 里引入 var.css 和 common.less

<!-- src/App.vue -->
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue';
</script><template><HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
</template><style>
@import url('@/assets/styles/common/var.css');
@import url('@/assets/styles/common/common.less');
</style>
复制代码

然后在 HelloWorld 里使用 less 变量, 可以看到配置生效了

<!-- src/components/HelloWorld.vue -->
<script setup lang="ts">
defineProps<{ msg: string }>();
</script><template><div class="title">{{ msg }}</div>
</template><style lang="less" scoped>
.title {color: @primary-color;
}
</style>
复制代码

3、切换主题色

新建 ThemeSetting 组件, 用于修改全局的主题色

<!-- src/components/ThemeSetting.vue -->
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({setup() {return {color: '#18a058',setColor(color: string) {document.documentElement.style.setProperty('--ant-primary-color',color);},};},methods: {handleChange(color: string) {this.color = color;this.setColor(this.color);},},
});
</script><template><input type="color" v-model="color" @change="handleChange(color)" />
</template><style lang="less" scoped></style>
复制代码

当通过颜色选择器修改颜色后, 可以看到 HelloWorld.vue 的颜色同时被修改了

4、antdv 主题色切换

1、引入 antdv

yarn add ant-design-vue
复制代码

在 main.ts 里引入非组件模块

// src/main.tsimport { createApp } from'vue';
importAppfrom'./App.vue';import { message } from'ant-design-vue';const app = createApp(App);
app.mount('#app');
app.config.globalProperties.$message = message;
复制代码

2、按需加载

安装 unplugin-vue-components

yarn add unplugin-vue-components -D
复制代码

在 vite 里使用插件

// vite.config.tsimport { defineConfig } from'vite';
import vue from'@vitejs/plugin-vue';
import path from'path';
importComponentsfrom'unplugin-vue-components/vite';
import { AntDesignVueResolver } from'unplugin-vue-components/resolvers';functionresolve(url: string): string {return path.resolve(__dirname, url);
}exportdefaultdefineConfig({plugins: [vue(),// 按需加载Components({resolvers: [AntDesignVueResolver({// 不加载css, 而是手动加载css. 通过手动加载less文件并将less变量绑定到css变量上, 即可实现动态主题色importStyle: false,}),],}),],...
});复制代码

3、主题色切换

全局引入 css 文件, 并通过 ConfigProvider 设置主题色

<!-- src/App.vue -->
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
import ThemeSetting from './components/ThemeSetting.vue';
import { ConfigProvider } from 'ant-design-vue';
ConfigProvider.config({theme: {primaryColor: '#18a058',},
});
</script><template><ThemeSetting /><HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
</template><style lang="less">
@import url('ant-design-vue/dist/antd.variable.less');
@import url('@/assets/styles/common/var.css');
@import url('@/assets/styles/common/common.less');
</style>
复制代码

在 HelloWorld 里使用 antd 组件

<!-- src/components/HelloWorld.vue -->
<script setup lang="ts">
defineProps<{ msg: string }>();
</script><template><div class="title">{{ msg }}</div><a-button type="primary">按钮</a-button>
</template><style lang="less" scoped>
.title {color: @primary-color;
}
</style>
复制代码

修改 setColor, 添加设置 antd 主题色功能

<script lang="ts">
import { ConfigProvider } from 'ant-design-vue';
import { defineComponent } from 'vue';
export default defineComponent({setup() {return {color: '#18a058',setColor(color: string) {document.documentElement.style.setProperty('--ant-primary-color',color);ConfigProvider.config({theme: {primaryColor: color,},});},};},
});
</script>
...

相关文章:

基于 vue3、vite、antdv、css 变量实现在线主题色切换

1、前言动态切换主题是一个很常见的需求. 实现方案也有很多, 如:编译多套 css 文件, 然后切换类名(需要预设主题, 不够灵活)less 在线编译(不兼容 ie, 性能较差)css 变量(不兼容 ie)但是这些基本都是针对 vue2 的, 我在网上并没有找到比较完整的解决 vue3 换肤的方案, 大多只处…...

“笨办法”学Python 3 ——练习 44 继承和组合

练习44 继承和组合 永远记住这一点&#xff1a;继承的大多数用法都可以用组合&#xff08;composition&#xff09;来简化或替换。并且无论如何都要避免多重继承。 内容提要&#xff1a; 1. 什么是继承&#xff1f; &#xff08;1&#xff09;隐式继承 &#xff08;2&#x…...

绕过安全狗拦截的SQL注入

目录 靶场环境及中间件 知识补充 判断存在注入 整形get类注入 字符型GET注入...

JAVA练习62-无重复字符的最长子串、最长回文子串

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、题目1-无重复字符的最长子串 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 二、题目2-最长回文子串 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总…...

【JavaWeb】复习重点内容

✅✅作者主页&#xff1a;&#x1f517;孙不坚1208的博客 &#x1f525;&#x1f525;精选专栏&#xff1a;&#x1f517;JavaWeb从入门到精通&#xff08;持续更新中&#xff09; &#x1f4cb;&#x1f4cb; 本文摘要&#xff1a;本篇文章主要分享JavaWeb的学习重点内容。 &a…...

基于粒子群改进的灰色神经网络的时间序列预测,PSO-GNN模型,神经网络案例之20

目标 灰色模型原理 神经网络原理 灰色神经网络原理 粒子群算法的原理 粒子群改进灰色神经网络原理 粒子群改进灰色神经网络的代码实现 效果图 结果分析 展望 灰色模型 基本思想是用原始数据组成原始序列(0),经累加生成法生成序列(1),它可以弱化原始数据的随机性,使其呈现…...

Java中的反射使用

1、获取Class对象的三种方式 1、对象调用Object类的getClass()方法&#xff08;对象.getClass()&#xff09; 2、调用类的class属性&#xff08;类名.class&#xff09; 3、调用Class类的静态方法&#xff08;Class.forName(“包名.类名”)&#xff09;常用 Student类 package…...

urho3d工具

AssetImporter 加载开放资源导入库支持的各种三维格式(http://assimp.sourceforge.net/)并保存Urho3D模型、动画、材质和场景文件。有关支持的格式列表&#xff0c;请参阅http://assimp.sourceforge.net/main_features_formats.html. Blender的另一种导出路径是使用Urho3D插件…...

HashMap数据结构

HashMap概述 HashMap是基于哈希表的Map接口实现的&#xff0c;它存储的是内容是键值对<key,value>映射。此类不保证映 射的顺序&#xff0c;假定哈希函数将元素适当的分布在各桶之间&#xff0c;可为基本操作(get和put)提供稳定的性能。 HashMap在JDK1.8以前数据结构和存…...

BFC的含义以及应用

什么是BFC? BFC全称是Block Formatting context&#xff0c;翻译过来就是块级格式化上下文。简单来说&#xff0c;BFC是一个完全独立的空间。让空间里的子元素不会影响到外面的布局。&#x1f603;&#x1f603;&#x1f603; 如何触发BFC呢&#xff1f; mdn给了如下方式&a…...

电脑技巧:分享8个Win11系统必备小技巧

目录 1、让任务栏显示“右键菜单” 2、任务栏置顶 3、还原经典右键菜单 4、Win11版任务管理器 5、新版AltTab 6、开始菜单不再卡 7、为Edge浏览器添加云母效果 8、自动切换日/夜模式 Win11在很多地方都做了调整&#xff0c;但由于涉及到诸多旧有习惯&#xff0c;再加上…...

C/C++每日一练(20230226)

目录 17. 电话号码的字母组合 37. 解数独 51. N 皇后 52. N皇后 II 89. 格雷编码 90. 子集 II 17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电…...

Vue 3第二章:Vite文件目录结构及SFC语法

文章目录1. Vite 文件目录结构2. Vue3 SFC 语法规范介绍1. Vite 文件目录结构 Vue3 并没有强制规定文件目录结构&#xff0c;开发者可以按照自己喜欢的方式组织代码。不过&#xff0c;通常情况下&#xff0c;我们会按照以下方式组织文件目录&#xff1a; ├── public │ …...

Leetcode 剑指 Offer II 016. 不含重复字符的最长子字符串

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长…...

TCP 的演化史-sack 与 reordering metric

就着 TCP 本身说事&#xff0c;而不是高谈阔论关于它是如何不合时宜&#xff0c;然后摆出一个更务虚的更新。 从一个 case 开始。 按照现在 Linux TCP(遵守 RFC) 实现&#xff0c;以下是一个将会导致 reordering 更新的 sack 序列&#xff1a; 考虑一种情况&#xff0c;这两个…...

【Spring6】| Spring的入门程序、集成Log4j2日志框架

目录 一&#xff1a;Spring的入门程序 1. Spring的下载 2. Spring的jar文件 3. 第一个Spring程序 4. 第一个Spring程序详细剖析 5. Spring6启用Log4j2日志框架 一&#xff1a;Spring的入门程序 1. Spring的下载 官网地址&#xff1a;https://spring.io/ 官网地址&…...

包子凑数(完全背包)

小明几乎每天早晨都会在一家包子铺吃早餐。 他发现这家包子铺有 N 种蒸笼&#xff0c;其中第 i种蒸笼恰好能放 Ai 个包子。 每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 X 个包子&#xff0c;卖包子的大叔就会迅速选出若干笼包子来&#xff0c;使得这若…...

Spring超级全家桶,学完绝对是惊艳面试官的程度

前言Spring框架自2002年诞生以来一直备受开发者青睐&#xff0c;它包括SpringMVC、SpringBoot、Spring Cloud、Spring Cloud Dataflow等解决方案。有人亲切的称之为&#xff1a;Spring 全家桶。很多研发人员把spring看作心目中最好的java项目&#xff0c;没有之一。所以这是重点…...

Redis主要数据类型

Redis 是一个数据结构服务器。 Redis 的核心是提供一系列本机数据类型&#xff0c;可帮助您解决从缓存到队列再到事件处理的各种问题Redis主要数据类型&#xff1a;String&#xff08;字符串&#xff09;&#xff0c;Lists&#xff08;列表&#xff09;&#xff0c;Sets&#x…...

【Linux | ELK 8.2】搭建ELKB集群Ⅰ—— 实验环境说明和搭建Elasticsearch集群

目录1. 实验环境1.1 实验工具1.2 操作系统1.3 架构版本、IP地址规划与虚拟机配置要求1.4 拓扑图1.5 其他要求2. 实验步骤2.1 安装Elasticsearch&#xff08;单节点&#xff09;&#xff08;1&#xff09;检查系统jdk版本&#xff08;2&#xff09;下载elasticsearch&#xff08…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...