大家好,我是前端架构师,关注微信公众号【程序员大卫】:
- 回复 [面试] :免费领取“前端面试大全2025(Vue,React等)”
- 回复 [架构师] :免费领取“前端精品架构师资料”
- 回复 [书] :免费领取“前端精品电子书”
- 回复 [软件] :免费领取“Window和Mac精品安装软件”
背景
做网站的时候,主题换肤是个很常见的需求——比如用户想要白天用浅色模式,晚上自动切换成护眼的暗黑模式;或者电商平台每逢大促需要临时换上节日皮肤。
今天我们就用最简单的代码,聊聊实现主题换肤的三种实用方案。
一、CSS 变量:新手必学的换肤方法
原理:就像给颜色起外号,换个外号就能批量改颜色。比如把「白色」定义成 --bg-color,需要白色的地方都用这个变量,想换颜色时只要改这个变量的值就行。
手把手教学
1. 创建项目(用 Vite 快速搭建)
打开终端输入:
pnpm create vite theme-change --template vue-ts
这样就创建了一个 Vue3 + TS 的项目,目录名是 theme-change。
2. 定义颜色变量
新建 src/enums/ThemeEnum.ts 文件:
// 就像给主题贴标签
export enum ThemeEnum {
LIGHT = "light", // 浅色模式(默认)
DARK = "dark" // 暗黑模式
}
3. 写 CSS 变量
新建 src/styles/theme.css:
/* 默认浅色模式 */
:root {
--bg-color: #fff; /* 背景白 */
--text-color: #333; /* 文字黑 */
}
/* 暗黑模式 */
[data-theme="dark"] {
--bg-color: #242424; /* 背景黑 */
--text-color: #fff; /* 文字白 */
}
再新建 src/styles/page.css:
/* 所有用到颜色的地方都用变量 */
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: all 0.3s; /* 加个过渡动画 */
}
4. 让按钮能切换主题
新建 src/hooks/useTheme.ts:
import { ref, computed } from "vue";
import { ThemeEnum } from "../enums/ThemeEnum";
// 当前主题(默认浅色)
const theme = ref<ThemeEnum>(ThemeEnum.LIGHT);
// 导出一个开关方法
export const useTheme = () => {
// 点击按钮时切换主题
const toggleTheme = () => {
const newTheme = theme.value === ThemeEnum.LIGHT ? ThemeEnum.DARK : ThemeEnum.LIGHT;
document.documentElement.setAttribute("data-theme", newTheme); // 修改 HTML 标签的属性
theme.value = newTheme; // 记住当前主题
};
// 判断是不是浅色模式
const isLightTheme = computed(() => theme.value === ThemeEnum.LIGHT);
return { toggleTheme, isLightTheme };
};
5. 在页面中使用
修改 App.vue:
<script setup lang="ts">
import { useTheme } from "./hooks/useTheme";
const { toggleTheme, isLightTheme } = useTheme();
</script>
<template>
<button @click="toggleTheme">
{{ isLightTheme ? '🌞 切暗黑' : '🌙 切浅色' }}
</button>
</template>
效果:点击按钮,页面背景和文字颜色会自动切换,还有过渡动画!
二、CSS 类名控制:处理特殊样式
如果遇到渐变背景、阴影这种不能用变量的情况,可以直接写两套 CSS。
比如卡片样式:
/* 浅色模式卡片 */
.card {
background: linear-gradient(90deg, #f0f0f0, #ffffff);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* 暗黑模式卡片 */
[data-theme="dark"] .card {
background: linear-gradient(90deg, #2d2d2d, #3d3d3d);
box-shadow: 0 2px 8px rgba(255,255,255,0.1);
}
注意:HTML 标签的 data-theme 属性变化时,所有带 [data-theme] 的样式都会自动生效!
三、切换组件:完全不同的页面结构
如果浅色和暗黑模式的页面结构完全不同,可以用 v-if 切换组件。
<script setup lang="ts">
import LightComponent from "./LightComponent.vue";
import DarkComponent from "./DarkComponent.vue";
import { useTheme } from "../hooks/useTheme";
const { isLightTheme } = useTheme();
</script>
<template>
<!-- 根据主题显示不同组件 -->
<LightComponent v-if="isLightTheme" />
<DarkComponent v-else />
</template>
总结
三种方法各有适用场景:
-
CSS 变量(推荐新手先用这个)
优点:改颜色最方便,代码量少
适用:简单颜色切换 -
CSS 类名
优点:能处理渐变、阴影等复杂样式
适用:需要整体替换样式的场景 -
切换组件
优点:页面结构可以完全不同
注意:组件太多会影响性能
实际开发小技巧:
- 把主题颜色都定义在 CSS 变量里,方便统一修改
- 在
localStorage保存用户选择(代码见源码) - 加个加载动画,让切换更流畅
GitHub 源码: github.com/zm8/wechat-…
[在线 Demo] codesandbox.io/p/devbox/rp…
如果本文对你有帮助,欢迎点赞❤️收藏⭐,也欢迎在评论区交流!