Angular Material 组件定制主题

摘要: 在使用 Angular Material 2+ 组件的时候,主题是一个十分灵活的定制。当我们需要让某个 Component 跟随主题的变化而变化时,我们需要进行定期,本文介绍其定制的原理。本文主要参考官方文档官方文档的源码

目标

在使用 Angular Material 2+ 时, 主题可以在运行时进行切换,那么如果我们希望某些组件的 UI 跟随主题的切换而变更,就需要定制 Component 对应的 SCSS 文件,根据官方文档介绍,这个样式文件必须为 SASS,所以我们使用 SCSS 来定义样式。

Mixin

这里使用 @mixin 来实现主题的引用,使用 @mixin 有诸多好处,具体可以参考本文,其好处主要是精简代码,增加代码重用等等。官方的解释是,通过 @mixin, 一旦更新主题,那么所有使用主题的样式都会自动更新。从而也就实现了将主题作为参数,成为网站的可配置选项。

实现方法

假设我们有一个 nav-bar 的 Component, 我们希望让其背景和文字颜色跟随主题变化。

Step1:定制 component 的样式

通过引用整体主题的样式来定义内部样式,比如 colorbackground colormat-color($primary)。同时将该样式定义为 @mixin, 其传入的参数为 $theme。通过这样定义,我们就可以动态的传入主题参数,然后获取相应的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Import all the tools needed to customize the theme and extract parts of it
@import '~@angular/material/theming';
// theme system: component theme!
@mixin nav-bar-theme($theme) {
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);

app-navbar {
color: mat-color($primary, default-contrast);

.docs-navbar, .docs-navbar-header {
background: mat-color($primary);
}
}
}

Step2:引用 mixin

我们需要传入我们当前的主题,所以只需要在我们主题定义的位置,将上面定制的组件的样式引用过来,并且传入当前主题即可。

1
2
3
4
5
6
7
8
// Import a pre-built theme
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
// Import your custom input theme file so you can call the custom-input-theme function
@import 'app/candy-carousel/nav-bar-them.scss';

// Using the $theme variable from the pre-built theme you can call the theming function
// 这里的 $theme 在预定义的主题中已经被定义,也就是将预定义的主题传入其中
@include nav-bar-them($theme);

最佳实践

动态主题

一般情况下都是在使用动态主题的时候才会用的这个功能,所以我们一般都需要配置整个项目可以切换主题。

参考 github (目前为开放)。

文件结构

对于 Component 的样式文件,官方给出了最佳实践。其样式分为 主题文件普通样式文件,然后所有的和主题的无关的样式都要放到普通样式文件中,而主题文件只存放被主题影响的样式。

对于文件的命名也有要求,比如我们 component 为 navbar.component.ts,那么:

  • 主题样式文件:_navbar-theme.scss
  • 普通样式文件:navbar.component.scss

这里主题样式文件名前需要加一个下划线。

如何使用主题中的颜色

我们可以使用 mat-color 来获取主题中的颜色:

1
2
3
4
5
6
7
8
9
10
// Import theming functions
@import '~@angular/material/theming';
// Import your custom theme
@import 'src/unicorn-app-theme.scss';

// Use mat-color to extract individual colors from a palette as necessary.
.candy-carousel {
background-color: mat-color($candy-app-primary);
border-color: mat-color($candy-app-accent, A400);
}