在Angular中创建一个与Angular Material主题兼容的库

    • Angularを使う

 

    • Angular Materialを使う

 

    • Angular Materialにカスタムテーマを設定する

 

    アプリケーションと同一環境で動作するライブラリでAngular Materialのテーマを利用

尽管有很多关于这个主题的文章,但我在创建一个库并在该库中使用Angular Material主题的过程中(无论是用日语还是英语)都找不到相关信息,所以我决定总结一下。我正在尝试使用Angular v6版本。

我会假设您已经安装了Angular的CLI,并且已经完成了最初的教程。在这个前提下,我将介绍一些技巧,使用TypeScript来开发某种框架的库,创建与主题对应的UI框架,并积极使用CSS in JS,以便将UI框架与外部库的主题进行匹配。我认为这些技巧在解决一般需求时也会很有参考价值。

创建一个图书馆

在当前以转译为前提的JavaScript中,最困难的是创建适用于转译前提环境的库。需要同时考虑库的创建者和使用者的构建环境。幸运的是,由于Java文化的影响力深厚,Angular作为一个代码生成器,其工作流程和命令行工具已经包含了相关功能。

无法单独创建库项目,需要首先创建一个使用该库的主应用程序,然后在主应用程序中构建库。库的名称是awesome-lib,前缀是al。最终的结构将是像这样的。

Screen Shot 2018-10-19 at 18.25.04.png

首先,我们将创建一个作为开发库基础的应用程序。稍后会提到,我们将使用SCSS作为样式表。嗯,即使忘记了,也不用担心,只需要稍后修改angular.json文件或组件中的样式表文件名,并将生成的各种css文件的扩展名更改为.scss,就可以重新进行了,不需要重新做。

$ ng new awesome-lib-sample --style=scss

接下来,在这个文件夹中创建一个库。如果忘记了前缀,它会变成”lib-“,听起来很土气,请务必记住前缀。

$ ng generate library awesome-lib --style=scss --prefix=al

好的。现在,库文件夹已经在”projects/awesome-lib”下创建好了。里面包含了库的package.json和其他一些内容,所以你可以添加额外需要的包并进行其他一些操作。

在母舰应用的根目录中完成诸如添加组件之类的操作。

$ ng generate component new-component --project=awesome-lib

可以在Root的母船应用文件夹下执行构建。按照以下方式进行构建,构建后的文件、project.json等将会在dist/awesome-lib文件夹及其子文件夹中生成。

$ ng build awesome-lib

这个dist/awesome-lib文件夹中包含了要在npm包中发布的内容。只需要在这个文件夹中使用npm publish命令,就可以快速地在npm上发布。

此外,使用方的母舰应用程序中

import { AwesomeLibModule } import "awesome-lib";

只需一个选项:

我们可以像安装已经发布的软件包一样,可以通过import命令导入。这是因为当我们使用ng generate library命令时,ng命令会自动在tsconfig.json文件中添加库的别名行。这样就可以在不实际部署的情况下测试生成的代码了。但是需要注意的是,在构建库的步骤中会有一个额外的步骤。

{
  "compilerOptions": {
    "paths": {
      "awesome-lib": [
        "dist/awesome-lib"
      ],
      "awesome-lib/*": [
        "dist/awesome-lib/*"
      ]
    }
  }
}

若将整体构成画成图,就是这个样子。

Screen Shot 2018-10-19 at 18.41.11.png

在浏览互联网时,可能会遇到一些旧的信息(例如创建文件夹或package.json之类的步骤),但最新的v6时代似乎是以下流程。

使用自己创建的库来利用Angular Material的主题。

如果只是简单地使用 Angular Material,从库中导入模块并按照 Angular Material 的教程操作,就能使用 mat- 前缀的各种功能,然后只需将其作为标签或指令进行使用。

然而,使用自定义库来使用Angular Material的主题颜色等需要花费一些时间和精力。虽然Angular Material中有官方说明,但解释不够详细,所以我会提供补充说明。

    Theming your custom components

如果要概括这个页面的内容,就是定义SCSS的mixin,并在根应用程序中设置Angular Material的主题设置时,以相同的方式为自己的组件设置主题。

Angular中SCSS的构建生命周期

当你创建Angular组件时,其中会设置样式表和HTML。.vue文件的单文件组件将各个元素拆分为不同的文件。你也可以将它们内嵌为字符串。

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'al-my-input',
  templateUrl: './my-input.component.html',
  styleUrls: ['./my-input.component.scss']
})
export class MyInputComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}

在使用库的情况下,通过ng build命令进行构建,.ts文件会被构建并转换为一个JavaScript文件。然而,麻烦之处在于在这里编写的SCSS文件将被转换为CSS in JS,并合并到JavaScript文件中。

换句话说,在这个时机上,像是动态的SCSS代码已经被“执行”了,所以在应用程序加载后设置主题是不可行的。

当然,CSS in JS作为一种方式具有优势,就像WebComponents一样,它可以封装CSS的影响范围,使得我们无需考虑整个应用的CSS模块化设计,只需轻松地编写组件专用的CSS。

Screen Shot 2018-10-19 at 19.02.36.png

Angular Material目前有使用两种类型的SCSS文件来定义组件(有些不相关的内容已经省略)。

/button
  _button-theme.scss
  button-module.ts
  button.scss
  button.ts

所以,button.scss是设置组件装饰器的地方。它包含了与主题无关的固定布局信息,例如宽度、z-index、圆角设置等等。另外还有一个scss文件_button-theme.scss,它包含了Angular Material官方指南中介绍的主题设置mixin。

这个包含mixin的代码,会从src/lib/core/theming/_all-theme.scss中被引入,并且会被单独编译到不同于库的.js文件中,在发布文件夹的顶部以_theming.scss的形式存放。

这是官方Angular Material主题设置示例中引入的theming的实体部分。我们将动态设置的颜色信息单独提取到另一个文件中,供应用程序调用。

@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-warn:    mat-palette($mat-red);

$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);

@include angular-material-theme($candy-app-theme);

换句话说,我们可以使用两个不同的SCSS文件来区分主题和布局。我们的目标是将库编译成JavaScript,并且将布局用的SCSS转换为JSS in JS的同时,让应用程序能够使用主题设置的SCSS。

Screen Shot 2018-10-19 at 19.08.20.png

在我的图书馆里也做同样的事情。

怎样才能创建一个_theming.scss文件呢?在每个库中都包含有SCSS。那么我们可以使用libsass进行构建吗?答案是否定的。调用libsass会进行函数展开操作,并最终生成普通的CSS,这不会生成可供应用程序使用的SCSS文件。

如果从头开始创建一个设置所有组件的单个SCSS文件,那将会变得非常复杂,尤其是当库中的模块增加时。至少,我们希望将动态主题的SCSS文件按组件进行分割。

我們還有一個能夠正好使用的工具,名為scss-bundle,它只處理@import,而不是完整地編譯SCSS,因此可以從許多SCSS文件中創建一個分發用的單一SCSS文件。

我们将在每个组件中创建一个mixin,使用Angular Material提供的$theme变量和mat-color函数来定义CSS。

@import '~@angular/material/theming';

@mixin my-inut-theme($theme, $guide-colors) {
  $primary: map-get($theme, primary);
  $accent: map-get($theme, accent);

  .al-input {
    background-color: mat-color($primary, 100);
  }
}

在项目的根目录中,我们将导入每个组件的主题用SCSS,并创建一个包含它们的mixin的主控文件。这将成为应用程序调用的入口点。

@import './src/lib/my-input/theme';

@mixin awesome-lib-theme($theme) {
  @include my-input-theme($theme, $guide-colors);
}

我也会写一个用于scss-bundle的配置文件。这样_theming.scss文件就会在分发文件夹的根目录中生成。重要的是,Angular Material提供的scss文件不会被包含在捆绑文件中。

{
   "entry": "projects/awesome-lib/_theming.scss",
   "dest": "./dist/awesome-lib/_theming.scss",
   "ignoredImports": ["~@angular/.*"]
}

最后,我在母舰示例应用程序的package.json中进行了一些更改,使得可以一起构建库和SCSS。我这次使用了scripts命令,但你也可以尝试使用npm-run-all等其他工具。

  "scripts": {
    "build-lib": "ng build awesome-lib",
    "postbuild-lib": "scss-bundle -c projects/awesome-lib/scss-bundle.config.json"
  },

最后,我们将在母舰的样式文件styles.scss中导入构建好的文件,并调用mixin。

@import '~@angular/material/theming';
@import '../dist/awesome-lib/theming';        // ←追加

// 省略

@include angular-material-theme($candy-app-theme);
@include awesome-lib-theme($candy-app-theme); // ←追加

现在,即使是自制的库,也可以与Angular Material的主题进行联动使用了。

总结

我以一种让任何人都能使用的方式介绍了在Angular Material中使用的技巧。

Angular Material自身以外にも便利なツールであるAngular CLIなどを活用しているような印象を受けます。ディレクトリ構成からビルド方法まで、すべてが現代的な手法とは異なるものとなっています。例えば、gulpを使用したり、bazelを利用するといった手法があります。そのため、解読には少し時間がかかるかもしれませんが、大規模なUI部品のコレクションを作りたい方や、Angular Materialと連携させてテーマに対応した追加コンポーネントのライブラリを作りたい方にとって、参考になると思います。私も時間を見つけて、Cheetah-GridのAngular版を作ろうと思っています。

广告
将在 10 秒后关闭
bannerAds