摘要:本文通过研究 Angular Material 的官方文档站 的源码,学习了其实现主题切换的方法。
原理概述
这里的原理十分简单,是通过动态替换整个网页的主题 css 文件来实现的,我们可以通过以下的 GIF 图来直观的感受一下:
通过切换主题,可以看到网页源码中的 css 在变化,当选择默认主题时,这个 css 的链接消失,从而实现了主题的切换。
SCSS 相关主题文件及编译
对于如何使用主题,我们可以通过官方文档学习。实现切换主题是基于基础配置的。首先我们来看 scss 文件的结构:
- styles.scss 配置默认主题,并引用主题文件
- _app-theme.scss 主要的主题配置文件,一方面配置全局的和主题相关的 css,另一方面引用 Component 中主题相关的配置,请参考Angular Material 组件定制主题
- assets/custom-themes/purple-green.scss 各个主题配置文件,每个主题单独一个文件,其配置和配置默认主题一致,不过这里需要加入 _app-theme.scss 的依赖,也就是说各个主题下,同样要应用 _app-theme.scss 的配置。实际上这些文件和 styles.scss 处于同等地位。
有了这些文件,基本的主题 SCSS 文件就准备好,下面我们需要编译生成 csss 的主题文件。
这里需要注意编译命令所执行的位置:
1 |
|
该文件 build-themes.sh
放置于 src/tools
下面,但是我们不能执行,需要在 package.json
中加入命令来执行: "build-themes": "bash ./tools/build-themes.sh",
为什么呢?因为 scss
文件又相互引用的关系,引用中使用了相对路径,这样就导致了路径基准需要一致,所以该命令需要在 src
目录下执行。 所以最好的方法就是在 package.json
中执行命令,这样以后集成部署都很方便。
编译完成之后我们会发现在 asset
目录下多处理若干个 css
文件,这些文件和不同主题是相对应的。其内容不仅包含了顶层主题的配置,还包含了各个模块自定义的和主题相关的css
。
StyleManager
该组件是主题切换的核心,我们来一下,该服务是如何实现动态管理主题的,其中的核心方法是 setStyle
和 removeStyle
。
1 | () |
通过源码我们可以看到,这里 setStyle
就是将指定主题元素的 DOM
元素的 href
连接动态设为所指定的主题。而这个方法就是根据主题的key 去寻找指定元素的 DOM
,该方法同时还要兼容默认主题的处理。 如果是默认主题,实际上这个DOM
应该不存在,所以我们需要处理没有该 DOM
的情形。
ThemePicker
相面我们来介绍一下主题切换器的实现方法。
Theme 模型和其存储
1 | export interface SiteTheme { |
这里使用 localStorage 来存储主题选择,这样可以在不清空缓存的情况下保持用户的主题选择。
1 | () |
Theme Picker 的实现
有了 styleManager
和主题的数据结构及存储方法,最终的主题选择器比较简单。
只需要一个下拉菜单,通过点击不同的主题来使用 styleManager
来配置相应的主题,同时进行储存即可。
1 | installTheme(theme: SiteTheme) { |
项目配置
当增加了新的 component theme style,需要重新编译样式文件。