Angular 不依赖第三方库实现动态 Theme
阅读需要 2 分钟
用户能够自己选择系统的外观一直以来都是很酷的功能,用户能实现完全的自定义,按自己的喜好设置不同的 theme。
在 Angular 构建的程序中也能很轻易实现。方法有很多种,比如利用Angular Material 组件库,里面内置了 theme 能用很少的代码实现动态 theme。
尽管利用组件库是一个不错的选择,但并非所有人都会使用 Material 样式。而且仅仅是为了实现动态 theme 就要引入一个组件库那就有点扯了,没人愿意这么做。
因此就有了用原生实现动态 theme 的骚操作 → 「Sass + CSS 自定义变量」
如果对 CSS 自定义属性很懵逼,点这里帮你解决疑惑。
单独用 Sass 变量也可以创建预设的 theme,但它无法用 JavaScript/TypeScript 控制,所以还得配合 CSS 自定义属性达到目的。
示例代码
骚操作
核心原理:结合 Scss map 和 CSS 自定义属性。
theme.scss
5-28行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// default colors
.theme-wrapper {
--cardColor: #CCC;
--cardBackground: #FFF;
--buttonColor: #FFF;
--buttonBackground: #FFF;
--navColor: #FFF;
--navBackground: #FFF;
--footerColor: #FFF;
--footerBackground: #FFF;
--footerAlignment: left;
}
$variables: (
--cardColor: var(--cardColor),
--cardBackground: var(--cardBackground),
--buttonColor: var(--buttonColor),
--buttonBackground: var(--buttonBackground),
--navColor: var(--navColor),
--navBackground: var(--navBackground),
--footerColor: var(--footerColor),
--footerBackground: var(--footerBackground),
--footerAlignment: var(--footerAlignment)
);
设置默认值并将其传入 sass map 中。
function.scss
2-4行
1
2
3
@function var($variable) {
@return map-get($variables, $variable);
}
创建一个函数从全局 sass map 中返回 css 自定义属性
card.component.scss
1-6行
1
2
3
4
5
6
7
8
9
@import '../../theme';
@import '../../functions';
.card {
background-color: var(--cardBackground);
color: var(--cardColor);
...
}
card 组件中 import function.scss 和 theme.scss Sass 文件,用来使用已定义的变量,该变量的值在重新提交主题选择组件表单是会更改。
theme-picker.component.ts
12-25行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
onSubmit(form) {
this.global(form.value);
}
global(stylesheet) {
...
// Navigation Styles
if (stylesheet.globalNavColor) {
this.themeWrapper.style.setProperty('--navColor', stylesheet.globalNavColor);
}
if (stylesheet.globalNavBackground) {
this.themeWrapper.style.setProperty('--navBackground', stylesheet.globalNavBackground);
}
...
}
global 方法检查该特定变量是否存在值,然后将每个 CSS 自定义属性值替换为新输入的变量值。
light/dark
模式 theme 的功能,具体技术细节会在「web 前端骚操作」知识星球中分享