主题
Vue 使用 SCSS 切换主题
最近想做一个切换主题的功能,但是发现 SCSS 和 Less 使用起来还有些区别,写完之后自己总结了一些,大家可以看看。
TIP
Less 篇请移步 vue 使用 less 切换主题
前置准备
首先需要确保项目中已经安装了 sass 和 sass-loader:
bash
npm install sass sass-loader -D配置步骤
1. 创建主题配置文件
在 src 下面创建 style 文件夹用于存放 CSS 文件,创建 theme.scss 和 handle.scss。
theme.scss
$themes 下面配置的 light 和 dark 是主题颜色的名字,这个可以自定义,使用时保持一致即可。
> `light` 和 `dark` 里面的配置名字也是**自定义**的,使用的时候保持一致即可。
scss
$white: #fff;
$black: #0e1225;
$themes: (
light: (
// 背景色
bg-color: $white,
// 文字颜色
font-color: #000,
// 渐变背景起始色
bg-color-start: #fefeff,
// 渐变背景结束色
bg-color-end: #e5f1fd,
// 代码块背景色
code-bg-color: #f5f7fa,
// 代码块文字颜色
code-font-color: #409eff,
),
dark: (
bg-color: #192342,
font-color: #c2c2c2,
bg-color-start: #0e1225,
bg-color-end: #0e1225,
code-bg-color: #2d2d2d,
code-font-color: #ccc,
),
);handle.scss
这个文件主要是采用 mixin 混入的方式将属性混入进去。
> `@mixin gradient_background`、`@mixin font_color` 这些名字也是自定义的,使用时对应即可(建议语义化,方便维护)。
scss
@import './theme.scss';
// 从主题色 map 中取出对应颜色
@function themed($key) {
@return map-get($theme-map, $key);
}
// 切换主题时获取不同的主题色值
@mixin themeify {
@each $theme-name, $theme-map in $themes {
// !global 把局部变量强升为全局变量
$theme-map: $theme-map !global;
// 判断 html 的 data-theme 的属性值 #{} 是 sass 的插值表达式
// & sass 嵌套里的父容器标识 @content 是混合器插槽,像 vue 的 slot
[data-theme='#{$theme-name}'] & {
@content;
}
}
}
// 获取渐变背景色
@mixin gradient_background($start-color, $end-color) {
@include themeify {
background: linear-gradient(to bottom, themed($start-color), themed($end-color)) !important;
transition: background-position 0.6s;
}
}
// 获取背景颜色
@mixin background_color($color) {
@include themeify {
background-color: themed($color) !important;
}
}
// 获取字体颜色
@mixin font_color($color) {
@include themeify {
color: themed($color) !important;
}
}
// 获取边框颜色
@mixin border_color($color) {
@include themeify {
border-color: themed($color) !important;
}
}2. 在 Vue 组件中使用
配置好之后就可以在想要设置颜色的 Vue 文件中引入使用了。
完整示例
vue
<template>
<div class="theme-container">
<button @click="change">切换主题</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const flag = ref(false)
onMounted(() => {
// 进入页面默认颜色
window.document.documentElement.setAttribute('data-theme', 'light')
})
const change = () => {
// 切换按钮
flag.value = !flag.value
if (flag.value) {
window.document.documentElement.setAttribute('data-theme', 'dark')
} else {
window.document.documentElement.setAttribute('data-theme', 'light')
}
}
</script>
<style lang="scss" scoped>
// 确保使用的是 scss
@import '../style/theme/handle.scss'; // 先引入
.theme-container {
width: 500px;
height: 500px;
// background_color 对应 handle.scss 文件中的属性
// 'bg-color' 对应 theme.scss 中的属性
@include background_color('bg-color');
@include font_color('font-color');
}
</style>核心原理
- 主题配置: 通过
$themesMap 定义多套主题色值 - 动态切换: 通过修改
html标签的data-theme属性来切换主题 - Mixin 混入: 使用
@mixin和@include实现样式的复用和动态应用
兼容性
TIP
这个方案同时支持 Vue 2 和 Vue 3
总结
使用 SCSS 的 Map 和 Mixin 特性,可以优雅地实现主题切换功能。相比 CSS 变量方案,这种方式在编译时就确定了样式,性能更好,且兼容性更强。
如果有问题,欢迎评论区或者私信我 💬
