Skip to content

Vue 使用 SCSS 切换主题

最近想做一个切换主题的功能,但是发现 SCSS 和 Less 使用起来还有些区别,写完之后自己总结了一些,大家可以看看。

TIP

Less 篇请移步 vue 使用 less 切换主题

前置准备

首先需要确保项目中已经安装了 sasssass-loader:

bash
npm install sass sass-loader -D

配置步骤

1. 创建主题配置文件

src 下面创建 style 文件夹用于存放 CSS 文件,创建 theme.scsshandle.scss

theme.scss

$themes 下面配置的 lightdark 是主题颜色的名字,这个可以自定义,使用时保持一致即可。

> `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>

核心原理

  1. 主题配置: 通过 $themes Map 定义多套主题色值
  2. 动态切换: 通过修改 html 标签的 data-theme 属性来切换主题
  3. Mixin 混入: 使用 @mixin@include 实现样式的复用和动态应用

兼容性

TIP

这个方案同时支持 Vue 2 和 Vue 3

总结

使用 SCSS 的 Map 和 Mixin 特性,可以优雅地实现主题切换功能。相比 CSS 变量方案,这种方式在编译时就确定了样式,性能更好,且兼容性更强。


如果有问题,欢迎评论区或者私信我 💬

如有转载或 CV 的请标注本站原文地址