如何利用 SCSS 实现一键换肤

环境准备

首先我们需要安装 scss 解析环境

npm i sass
// 注意 sass-loader 安装需要指定版本 如果安装最新版本会报错 this.getOptions 这个方法未定义
npm i -D sass-loader@10.1.0
// 利用 normalize.css 初始化页面样式
npm i -S normalize.css

小技巧

这里讲一个小技巧,定义的时候可以先定义一个基准变量 base-param 然后其他状态的值可以依赖这个 base-param 进行缩放或放大实现。比如不同大小规模的字体可以采用这种方法。

// 行高
$line-height-base: 1.5 !default;
$line-height-lg: 2 !default;
$line-height-sm: 1.25 !default;
// ./style/settings/variable.scss

// 字体颜色
$info: #17a2b8 !default;
$danger: #dc3545 !default;

// 字体大小 浏览器默认 16px
$font-size-base: 1rem !default;
$font-size-lg: $font-size-base * 1.25 !default;
$font-size-slg: $font-size-base * 1.75 !default;

// 字重
$font-weight-normal: 400 !default;
$font-weight-bold: 600 !default;

定义一个入口文件

// ./style/theme/index.scss

@import "../settings/variable.scss";

$themes-color: (
  default: (
    // 全局样式属性
    color: $info,
    font-weight: $font-weight-normal,
    font-size: $font-size-lg,
  ),
  old: (
    color: $danger,
    font-weight: $font-weight-bold,
    font-size: $font-size-slg,
  ),
  // ... 可自定义其他主题
);
//注意需要在./style/theme下创建对应的目录default、old
//用户vue.config.js获取目录名

vue.config.js 配置项处理

我们不想每次都引入 CSS 变量,可以在配置项中利用 CSS 插件自动注入全局变量样式。

// vue.config.js

module.exports = {
  css: {
    loaderOptions: {
      scss: {
        // 注意: 在 sass-loader v8 中,这个选项是 prependData
        additionalData: `@import "@/style/theme/index.scss";`,
      },
    },
  },
};

主题色切换

主题色定义好之后就需要对他进行切换了。这也是一键换肤最核心的逻辑。

  • 在 App.vue 文件下的 mounted 中将 body 添加一个自定义的 data-theme 属性,并将其设置为 default
// App.vue mounted() { document .getElementsByTagName("body")[0]
.setAttribute("data-theme", "default"); },
  • 利用 webpack 自定义插件遍历主题目录文件,自动生成自定义主题目录数组
// vue.config.js
const fs = require("fs");
const webpack = require("webpack");

// 获取主题文件名
const themeFiles = fs.readdirSync("./src/style/theme");
let ThemesArr = [];
themeFiles.forEach(function (item, index) {
  let stat = fs.lstatSync("./src/style/theme/" + item);
  if (stat.isDirectory() === true) {
    ThemesArr.push(item);
  }
});

module.exports = {
  css: {...},
  configureWebpack: (config) => {
    return {
      plugins: [
        // 自定义webpack插件
        new webpack.DefinePlugin({
          THEMEARR: JSON.stringify(ThemesArr),
        }),
      ],
    };
  },
};
  • 切换 js 逻辑实现
    初始化页面的时候,获取到默认主题
// Home.vue
//template
<div @click="onConfirm('old')">变old</div>
<div @click="onConfirm('default')">default</div>


//script
data(){
    return {
      themeValue:'',
      list:[''],
      currentTheme:'',
      currentThemeIndex:0
    }
  },
mounted() {
  this.themeValue = THEMEARR;
  this.currentThemeIndex = this.themeValue.findIndex(
    (theme) => theme === "default"
  );
  this.currentTheme = this.themeValue[this.currentThemeIndex];
},

把选择的主题赋值给自定义属性 data-theme

// Home.vue

// 核心切换逻辑
methods: {
  onConfirm(currentTheme) {
    this.currentTheme = currentTheme;
    this.currentThemeIndex = this.themeValue.findIndex(
      (theme) => theme === currentTheme
    );
    document
      .getElementsByTagName("body")[0]
      .setAttribute("data-theme", THEMEARR[this.currentThemeIndex]);
  },
}

根vue文件下设置全局的样式

//app.vue
@import "./style/theme/index.scss";
@mixin themify() {
  @each $theme-name, $map in $themes-color {
    // & 表示父级元素  !global 表示覆盖原来的
    [data-theme="#{$theme-name}"] & {
      $theme-map: () !global;
      // 循环合并键值对
      @each $key, $value in $map {
        $theme-map: map-merge(
          $theme-map,
          (
            $key: $value,
          )
        ) !global;
      }
      // 表示包含 下面函数 themed()
      @content;
    }
  }
}

@function themed($key) {
  @return map-get($theme-map, $key);
}

#app{
  @include themify() {
    color: themed("color");
    font-weight: themed("font-weight");
    font-size: themed("font-size");
  }
}

学习其中sass的知识

  • 使用 @each 循环
    1.循环一个 list: 类名为 icon-10px 、icon-12px、icon-14px 写他们的字体大小写法就可以如下:
    在这里插入图片描述
    2、循环一个 map:类名为 icon-primary、icon-success、icon-secondary 等,但是他们的值又都是变量,写法如下:
    在这里插入图片描述

  • map-get

map-get(map,key) 函数的作用是根据 key 参数,返回 key 在 map 中对应的 value 值。如果 key 不存在 map 中,将返回 null 值。此函数包括两个参数:

map:定义好的 map。key:需要遍历的 key。

假设要获取 facebook 键值对应的值 #3b5998,我们就可以使用 map-get() 函数来实现:
在这里插入图片描述

  • 使用&嵌套覆盖原有样式

当一个元素的样式在另一个容器中有其他指定的样式时,可以使用嵌套选择器让他们保持在同一个地方。.no-opacity &相当于.no-opacity .foo。
在这里插入图片描述

  • map-merge

合并两个 map 形成一个新的 map 类型,即将 map2 添加到 map1的尾部

$font-sizes: ("small": 12px, "normal": 18px, "large": 24px)
$font-sizes2: ("x-large": 30px, "xx-large": 36px)
map-merge($font-sizes, $font-sizes2)
结果: "small": 12px, "normal": 18px, "large": 24px,
"x-large": 30px, "xx-large": 36px
  • @content

@content 用在 mixin 里面的,当定义一个 mixin 后,并且设置了 @content;@include 的时候可以传入相应的内容到 mixin 里面
在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Vue 3中使用TypeScript和Sass配置换肤功能,可以按照以下步骤进行操作: 1. 安装依赖: 在项目根目录下打开终端,执行以下命令安装所需的依赖: ```bash npm install sass --save-dev npm install sass-loader --save-dev ``` 这将安装Sass解析器和Sass加载器。 2. 配置webpack: 在Vue 3中,使用了Vite作为默认的开发服务器和构建工具,不再使用webpack配置文件来自定义构建配置。但我们可以通过`vite.config.js`文件来进行一些自定义配置。 在项目根目录下创建`vite.config.js`文件,并添加以下内容: ```javascript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], css: { preprocessorOptions: { scss: { additionalData: `@import "@/styles/variables.scss";` // 引入全局变量文件 }, }, }, }) ``` 上述配置中,我们使用`@vitejs/plugin-vue`插件来支持Vue相关的开发。在`css`选项中,我们使用`preprocessorOptions`来设置Sass的配置,这里我们引入了一个全局变量文件`variables.scss`,你可以根据自己的需求来修改引入的文件路径。 3. 创建样式文件: 在项目的`src/styles`目录下创建一个名为`variables.scss`的文件,并定义一些换肤所需的变量,例如: ```scss // variables.scss $primary-color: #00aaff; $secondary-color: #ff00aa; ``` 4. 在组件中使用样式: 在Vue组件中使用Sass样式时,可以直接在`<style>`标签中编写Sass代码,并使用定义的变量。例如: ```vue <template> <div class="app"> <h1 :style="{ color: primaryColor }">Hello World</h1> <button :style="{ background: secondaryColor }">Change Theme</button> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ name: 'App', data() { return { primaryColor: 'var(--primary-color)', secondaryColor: 'var(--secondary-color)', }; }, }); </script> <style lang="scss"> .app { h1 { font-size: 24px; } button { padding: 10px; color: white; cursor: pointer; } } </style> ``` 在上述示例中,我们通过`:style`绑定属性来动态改变标题和按钮的样式,使用了Sass样式和定义的变量。 现在,你可以根据需要在Vue 3项目中使用TypeScript和Sass来实现换肤功能了。希望对你有所帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值