Vue + Sass 动态换肤

根据不同的配色方案,在前端实现动态切换系统主题颜色。

大概的思路就是给html根标签设置一个data-theme属性,然后通过js切换data-theme的属性值,

# 创建项目

npm install -g @vue/cli
vue create vue-theme

# 安装Sass依赖

npm install -D sass-loader sass

# 开始

  1. 新建一个_theme.scss文件,在里面配置不同的颜色方案,不同的配色方案,颜色变量要一一对应。

$themes: (
  light: (
    // 字体颜色
    main_color: #1E1E20,

    // 背景颜色
    main_background: #fff,

    // 边框颜色
    main_border_color: #E6E6E6,
  ),

  dark: (
    main_color: #fff,

    main_background: #1E1E20,

    main_border_color: #4a4a4a,
  )
);

注意,scss文件名建议用下划线开头,如_themes.scss,防止执行时被编译成单独的css文件。

  1. 在新建一个_theme-handle.scss文件,用来操作变量
@import './_themes.scss';

// 遍历主题
@mixin themeify {
  @each $theme-name, $theme-map in $themes {
    // !global 把局部变量强升为全局变量
    $theme-map: $theme-map !global;
    // 判断 html 的 data-theme 的属性值
    [data-theme="#{$theme-name}"] & {
      @content;
    }
  }
}

// 声明一个根据 Key 获取颜色的 function
@function themed($key) {
  @return map-get($theme-map, $key);
}

// 获取背景颜色
@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;
  }
}
  1. Vue组件中使用:
<style lang="scss" scoped>
@import "@/assets/styles/_theme-handle.scss";

.scss-container {
  font-size: 18px;
  @include font_color("main_color");
  @include background_color("main_background");
}
</style>
  1. 动态切换主题:
<template>
  <div class="scss-container">
    <p>Vue + Scss 动态换肤</p>
    <button @click="() => changeTheme('light')">浅色主题</button>
    <button @click="() => changeTheme('dark')">深色主题</button>
  </div>
</template>

<script>
export default {
  methods: {
    changeTheme(type) {
      document.documentElement.setAttribute("data-theme", type)
    }
  }
}
</script>