共计 5798 个字符,预计需要花费 15 分钟才能阅读完成。
上一篇介绍了如何自定义 Material 主题,当初来看看怎么定义多个主题,并在运行时动静切换。
能够采纳官网介绍的类名包裹形式,或者咱们也能够事后编译,按需引入。话不多说,let’s rock the code!????
按类名切换明暗格调
如上篇所言,咱们首先就来实现怎么切换网站的暗黑主题。
留神✨:能够在 styles.scss 中调用 angular-material-theme
mixin 屡次,来生成多套不同的主题,但 @mat-core
始终只能调用一次。
创立两个主题
咱们先创立两个主题,一个亮堂格调的主题作为默认,另一个暗黑格调的主题放在 .unicorn-dark-theme
这个类名中。这样一来,任何在该类名内的元素,都会利用暗黑格调的主题款式。
@import '~@angular/material/theming';
@include mat-core();
// 定义一个自定义色彩配置 ( 和前一篇一样)$candy-app-primary: mat-palette($mat-indigo);
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
$candy-app-theme: mat-light-theme((
color: (
primary: $candy-app-primary,
accent: $candy-app-accent,
)
));
// 蕴含默认主题色彩以及文字排版
@include angular-material-theme($candy-app-theme);
// 定义另一个暗黑格调的主题
$dark-theme: mat-dark-theme((
color: (
primary: $candy-app-primary,
accent: $candy-app-accent,
)
));
// 用一个类名包裹暗黑主题款式
.unicorn-dark-theme {@include angular-material-color($dark-theme);
}
留神✨:暗黑主题采纳 angular-material-color
,而不是默认主题应用的 angular-material-theme
,因为后者不光会生成主题色彩的款式,还会生成其余款式。这里只须要扭转色彩即可。而如果须要独自扭转文字排版,能够应用 angular-material-typography
。相似的,细粒度的自定义某组件也是同理(例如:mat-button-theme
/ mat-button-color
/ mat-button-typography
)。
额定解决基于覆盖层的组件
因为基于覆盖层的组件(例如:menu、select、dialog 等)不是被应用程序的根组件包裹,而是和根组件平级的 <div class="cdk-overlay-container">
节点。因而,要让它们也能依据类名切换主题款式,须要做一点额定的解决:
import {OverlayContainer} from '@angular/cdk/overlay';
@Component({// ...})
export class AppComponent {
// 用以绑定类名
isDarkMode = false;
constructor(private overlayContainer: OverlayContainer) {}
private processOverlayBaseComponentTheme(checked: boolean) {
// 获取这个 div 元素
const overlayContainerElement = this.overlayContainer.getContainerElement()
const themeWrapperClassName = 'unicorn-dark-theme'
if (checked) {overlayContainerElement.classList.add(themeWrapperClassName);
} else {overlayContainerElement.classList.remove(themeWrapperClassName);
}
}
}
动静切换类名
通过 Angular 类名绑定,来切换不同的主题:
<div [class.unicorn-dark-theme]="isDarkMode">
<!-- 受主题切换影响的元素和组件 -->
</div>
当初,就能够在两个主题之间自在切换了!????
看看成果:
多整几个
尽管下面咱们实现了动静主题切换,不过只有暗黑 / 亮堂的两个主题重复横跳显得不太够看。所以,当初到了整活儿工夫,一次性整它十个色彩!
创立多个主题
相比创立两个主题时手动去创立,创立一个多个主题的 styles.scss,咱们就利用 Sass 的循环来实现,次要分为几步:
-
自定义主题的结尾操作都一样,先引入
mat-core
,并先定义一个默认主题:@import '~@angular/material/theming'; @include mat-core(); // 默认主题色彩配置 $candy-app-primary: mat-palette($mat-indigo); $candy-app-accent: mat-palette($mat-pink, A200, A100, A400); $candy-app-theme: mat-light-theme(( color: ( primary: $candy-app-primary, accent: $candy-app-accent, ) )); // 生成默认主题款式 (色彩,文字排版,间距) @include angular-material-theme($candy-app-theme); @include app-component-color($candy-app-theme); @include theme-test-color($candy-app-theme);
-
创立一个 map 对象,在这个 map 中定义各个主题配置。每个主题配置的
key
就是这个主题的 class 类名:$app-themes: (indigo-pink : (primary-base: $mat-indigo, accent-base: $mat-pink), deeppurple-amber: (primary-base: $mat-deep-purple, accent-base: $mat-amber), blue-yellow : (primary-base: $mat-blue, accent-base: $mat-yellow), pink-bluegrey : (primary-base: $mat-pink, accent-base: $mat-blue-gray,), purple-green : (primary-base: $mat-purple, accent-base: $mat-green), );
-
通过
@each
循环,创立明暗个五个主题色彩:@each $css-class, $theme in $app-themes {$primary: mat-palette(map-get($theme, primary-base)) $accent: mat-palette(map-get($theme, accent-base)) // key 值作为类名 .#{$css-class} { $light-theme: mat-dark-theme(( color: ( primary: $primary, accent: $accent, ) )); // 生成色彩款式 @include angular-material-color($light-theme); // 增加两个业务组件测试主题适配 @include app-component-color($light-theme); @include theme-test-color($light-theme); } // key 值作为类名 .#{$css-class}-dark { $dark-theme: mat-dark-theme(( color: ( primary: $primary, accent: $accent, ) )); // 生成色彩款式 @include angular-material-color($dark-theme); // 增加两个业务组件测试主题适配 @include app-component-color($dark-theme); @include theme-test-color($dark-theme); } }
动静切换主题
通过扭转 root 元素的 class,来动静切换域名:
<div [class]="currentTheme">
<!-- 受主题切换影响的元素和组件 -->
</div>
themelist = [
"amber-lime",
"amber-lime-dark",
"deeppurple-amber",
"deeppurple-amber-dark",
"blue-yellow",
"blue-yellow-dark",
"pink-bluegrey",
"pink-bluegrey-dark",
"purple-green",
"purple-green-dark"
]
switchTheme(theme: string) {if (this.currentTheme)
this.overlayContainerEle.classList.remove(this.currentTheme);
this.currentTheme = theme
this.overlayContainerEle.classList.add(this.currentTheme);
}
ok,当初咱们有了 10 套主题!
不过能够看到,当初编译打包后的 styles.css 和 styles.js,未压缩的状况下,快高达 1MB 了(每个主题会减少 css 文件 50kb 大小)。所以,咱们试着懒加载它们。
懒加载动静切换
当初咱们曾经能够动静的切换主题了,可只有两三个主题还好,如果我的应用程序,要提供很多的主题搭配,让用户自在选用呢,styles.scss 一次蕴含这么多份主题款式,切实有损加载性能(每个主题减少 50kb)。
遇到这种状况,咱们能够事后编译好须要用到主题,在运行时动静切换它们,就能够按需加载了。
-
首先在 src > theme 文件夹中创立几个主题文件,例如这个 green-amber-dark.scss:
@import "~@angular/material/theming"; @import "../app/app.component.theme.scss"; @import "../app/component/theme-test/theme-test.component.theme"; $green-primary: mat-palette($mat-green); $amber-accent: mat-palette($mat-amber); $green-amber-dark-theme: mat-dark-theme(( color: ( primary: $green-primary, accent: $amber-accent ) )); @include angular-material-theme($green-amber-dark-theme); // 增加两个业务组件测试主题适配 @include app-component-color($green-amber-dark-theme); @include theme-test-color($green-amber-dark-theme);
-
而后,在 angular.json > projects > architect > build > styles 中,新增刚刚创立的主题文件,inject 设置为 false,意味着它只会被打包为独自的 css 文件,但不会被引入我的项目中:
"styles": [ "src/styles.scss", { "input": "src/theme/green-amber-theme.scss", "inject": false } ],
-
最初,通过给 <link> 动静赋值即可:
switchTheme(theme: string): void { const id = 'lazy-load-theme'; const link = document.getElementById(id); // 第一次切换,新建一个 link 元素 if (!link) {const linkEl = document.createElement('link'); linkEl.setAttribute('rel', 'stylesheet'); linkEl.setAttribute('type', 'text/css'); linkEl.setAttribute('id', id); linkEl.setAttribute('href', `${theme}-theme.css`); document.head.appendChild(linkEl); } else { // 替换 link 元素的 href 地址 (link as HTMLLinkElement).href = `${theme}-theme.css`; } }
这样就实现了主题文件的懒加载,不过须要留神的是,默认的主题文件仍旧须要在 styles.scss 中援用,它也懒加载的话,会导致首次加载时页面闪动。
小结
本篇介绍了如何动静切换主题,渐进的包含了三种状况:
- 网站只须要在亮堂和暗黑模式下切换主题,那么只须要通过一个独特的类名包裹主题即可,切换时只是切换类名即可
- 网站若是须要预设多个主题,能够利用 Sass 的 @each 办法,来批量生成,再依据类名动静切换。
- 如果网站的主题量很大或者可预感的会一直减少,又或者想要尽量多的优化加载性能,能够采纳动静加载主题文件的形式,动静的管制一个 link 标签即可。
本篇的三种状况,能够参照 Github 示例,按 branch 切换
成果能够参考 成果展现,点击右上角工具栏能够切换各个主题。
有时候我的项目里可不止用上了 Material 的组件库,适配第三方组件库的主题,不像本人的业务组件,能够随便更改,就要另辟蹊径了,对于 Material 主题零碎的工程实际,咱们下一篇见!????