1. 样式目录文件架构
packages/theme-chalk 目录结构:
├── packages
│ ├── theme-chalk
│ │ ├── src
│ │ │ ├── common
│ │ │ │ └── var.scss // SCSS变量配置文件
│ │ │ ├── mixins
│ │ │ │ ├── _var.scss // CSS变量相关的SCSS自定义函数
│ │ │ │ ├── config.scss // 配置文件
│ │ │ │ ├── function.scss // 全局的SCSS自定义函数
│ │ │ │ └── mixins.scss // BEM相关函数
│ │ │ ├── base.scss // 基础必须要引用的文件
│ │ │ ├── button.scss // 按需导入组件的 CSS 文件
│ │ │ ├── index.scss // 全量导入组件库的 CSS 入口文件
│ │ │ ├── var.scss // CSS 变量配置文件
│ │ │ ├── reset.scss // 默认样式重置配置文件
通过 theme-chalk/src/common/var.scss 中的 SCSS 变量配置在 theme-chalk/src/var.scss 中进行封装生成全局的 CSS 变量,在这个过程中使用到的有关生成 CSS 变量的 SCSS 自定义函数则在 theme-chalk/src/mixins/_var.scss 文件中进行设置。
因为要实现按需导入组件,所以各个组件单独一个 CSS 文件。例如 Button 组件的 CSS 文件对应就是 button.scss 文件。在编写组件 CSS 样式中需要使用到的 BEM 的 SCSS 自定义函数则在 theme-chalk/src/mixins/mixins.scss 中,其他的 SCSS 自定义函数则在 theme-chalk/src/mixins/function.scss 中。
base.scss 文件则是引用那些必须的文件,比如 var.scss 文件是必须,这类文件则放在 base.scss 文件中。在全量导入组件库的 CSS 入口文件 index.scss 中最先引入的便是 base.scss 文件。将来组件的自己的按需导入的 CSS 文件,例如 packages/components/button/style/index.ts 也就是 Button 组件的按需导入的 CSS 文件,其中也是需要最先导入 base.scss 文件,再进行导入 button.scss 文件。
2. SCSS 样式变量
2.1 设置颜色 SCSS 变量
// packages/theme-chalk/src/common/var.scss
@use 'sass:map';
// 默认颜色映射,使用 deep-merge 来允许用户自定义颜色映射覆盖默认值
$colors: () !default;
$colors: map.deep-merge(
(
// 白色和黑色作为基本颜色选项
'white': #ffffff,
'black': #000000,
// 为每种主题类型定义一个基础颜色
'primary': (
'base': #409eff,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #e6a23c,
),
'error': (
'base': #f56c6c,
),
'info': (
'base': #909399,
),
),
$colors
);
// 主色调
$color-white: map.get($colors, 'white') !default; // 白色
$color-black: map.get($colors, 'black') !default; // 黑色
// 应用场景颜色
$color-primary: map.get($colors, 'primary', 'base') !default; // 主要颜色,默认使用'base'色调
$color-success: map.get($colors, 'success', 'base') !default; // 成功状态颜色,默认使用'base'色调
$color-warning: map.get($colors, 'warning', 'base') !default; // 警告状态颜色,默认使用'base'色调
$color-error: map.get($colors, 'error', 'base') !default; // 错误状态颜色,默认使用'base'色调
$color-info: map.get($colors, 'info', 'base') !default; // 信息状态颜色,默认使用'base'色调
先设置一个总的 $colors 变量,然后再单独设置每一个具体类型的变量,变量值是继承 $colors 变量,这样将来只要修改 $colors 中的变量值,后续每个继承 $colors 变量的 SCSS 变量都将发生改变。
2.2 设置多种类型主题
- 定义主题类型
// packages/theme-chalk/src/common/var.scss
// 定义可用的主题类型
$types: primary, success, warning, error, info;
- 扩展颜色变量
// packages/theme-chalk/src/common/var.scss
@use 'sass:math';
/**
* 该@mixin用于根据指定的颜色类型、级别和混合模式,创建一个新颜色等级并将其添加到全局颜色地图中。
* @param $type {string} - 颜色的类型(例如:primary, success等)。
* @param $number {int} - 颜色的级别,用于计算颜色的混合程度。
* @param $mode {string} - 混合模式,默认为'light'。可用于指定颜色是明度混合还是饱和度混合等。
* @param $mix-color {color} - 用于混合的颜色,默认为白色($color-white)。
*/
@mixin set-color-mix-level(
$type,
$number,
$mode: 'light',
$mix-color: $color-white
) {
// 深度合并颜色地图,添加新的颜色等级
$colors: map.deep-merge(
(
$type: (
'#{$mode}-#{$number}':
mix(
$mix-color,
map.get($colors, $type, 'base'),
math.percentage(math.div($number, 10))
),
),
),
$colors
) !global; // 将局部变量转换为全局变量,确保新的颜色等级可以在整个项目中使用
}
@each $type in $types {
@for $i from 1 through 9 {
@include set-color-mix-level($type, $i, 'light', $color-white);
}
}
执行上述代码就等于往各类型中添加新的变量颜色,效果如下:
$colors:
(
'primary': (
'base': #409eff,
'light-1': 通过mix生成的新颜色,
'light-2': 通过mix生成的新颜色,
'light-3': 通过mix生成的新颜色,
// ...
),
'success': (
'base': #67c23a,
'light-1': 通过mix生成的新颜色,
'light-2': 通过mix生成的新颜色,
'light-3': 通过mix生成的新颜色,
// ...
),
'warning': (
'base': #e6a23c,
'light-1': 通过mix生成的新颜色,
'light-2': 通过mix生成的新颜色,
'light-3': 通过mix生成的新颜色,
// ...
),
// ...
)
2.3 生成全局类型主题 SCSS 变量
// src/var.scss
@use 'common/var' as *;
@use 'mixins/var' as *;
// 公共变量
:root {
@include set-css-var-value('color-white', $color-white);
@include set-css-var-value('color-black', $color-black);
}
// 亮色模式
:root {
color-scheme: light;
// --v-color-#{$type}
// --v-color-#{$type}-light-{$i}
@each $type in $types {
@include set-css-color-type($colors, $type);
}
}
// src/mixins/_var.scss
@use 'sass:map';
@use 'function' as *;
// @include set-css-var-value(('color', 'primary'), red);
// --v-color-primary: red;
@mixin set-css-var-value($name, $value) {
#{joinVarName($name)}: #{$value};
}
@mixin set-css-var-value($name, $value) {
#{joinVarName($name)}: #{$value};
}
// @include set-css-var-type('color', 'primary', $map);
// --v-color-primary: #{map.get($map, 'primary')};
@mixin set-css-var-type($name, $type, $variables) {
#{getCssVarName($name, $type)}: #{map.get($variables, $type)};
}
@mixin set-css-color-type($colors, $type) {
@include set-css-var-value(('color', $type), map.get($colors, $type, 'base'));
@each $i in (3, 5, 7, 8, 9) {
@include set-css-var-value(
('color', $type, 'light', $i),
map.get($colors, $type, 'light-#{$i}')
);
}
@include set-css-var-value(
('color', $type, 'dark-2'),
map.get($colors, $type, 'dark-2')
);
}
// src/mixins/function.scss
/**
* 函数用于将给定列表中的项目连接成一个变量名。
* @param $list - 一个包含要连接的字符串的列表。
* @return $name - 连接后的变量名,以"--"和配置中的命名空间开头,每个列表项之间用"-"连接。
*/
@function joinVarName($list) {
// 初始化变量名,以"--"和配置中的命名空间开头
$name: '--' + config.$namespace;
// 遍历列表中的每个项目
@each $item in $list {
// 如果项目不为空,则将其添加到变量名中
@if $item != '' {
$name: $name + '-' + $item;
}
}
// 返回连接后的变量名
@return $name;
}
// getCssVarName('button', 'text-color') => '--v-button-text-color'
@function getCssVarName($args...) {
@return joinVarName($args);
}
// src/base.scss
@use 'var.scss';
// src/index.scss
@use './base.scss';
@use './button.scss';
运行play项目,可以在控制台看到
2.4 分组生成 SCSS 变量
以分组的模式生成不同分组的 CSS 变量
// src/common/var.scss
// 文本颜色
$text-color: () !default;
$text-color: map.merge(
(
'primary': #303133,
'regular': #606266,
'secondary': #909399,
'placeholder': #a8abb2,
'disabled': #c0c4cc,
),
$text-color
);
// 边框颜色
$border-color: () !default;
$border-color: map.merge(
(
'': #dcdfe6,
'light': #e4e7ed,
'lighter': #ebeef5,
'extra-light': #f2f6fc,
'dark': #d4d7de,
'darker': #cdd0d6,
),
$border-color
);
// 填充颜色
$fill-color: () !default;
$fill-color: map.merge(
(
'': #f0f2f5,
'light': #f5f7fa,
'lighter': #fafafa,
'extra-light': #fafcff,
'dark': #ebedf0,
'darker': #e6e8eb,
'blank': #ffffff,
),
$fill-color
);
// 背景颜色
$bg-color: () !default;
$bg-color: map.merge(
(
'': #ffffff,
'page': #f2f3f5,
'overlay': #ffffff,
),
$bg-color
);
// src/var.scss
:root {
color-scheme: light;
// --v-text-color-#{$type}
@include set-component-css-var('text-color', $text-color);
// --v-border-color-#{$type}
@include set-component-css-var('border-color', $border-color);
// Fill --v-fill-color-#{$type}
@include set-component-css-var('fill-color', $fill-color);
// Background --v-bg-color-#{$type}
@include set-component-css-var('bg-color', $bg-color);
}
// src/mixins/_var.scss
/**
* 设置分组的CSS变量
* @param $name - 分组名称,用于生成CSS变量名。
* @param $variables - 一个映射表,包含要设置的变量名和其值。
* 该mixin遍历$variables映射表,为每个键值对生成相应的CSS变量。如果键是"default",
* 则设置基础的CSS变量;否则,设置带有特定后缀的CSS变量。
*/
@mixin set-component-css-var($name, $variables) {
@each $attribute, $value in $variables {
// 根据$attribute的值决定是设置基本变量还是特定属性的变量
@if $attribute == 'default' {
#{getCssVarName($name)}: #{$value}; // 设置默认的CSS变量
} @else {
#{getCssVarName($name, $attribute)}: #{$value}; // 设置具有特定后缀的CSS变量
}
}
}
运行play项目,可以在控制台看到