【问题标题】:How can I make a theme-able Angular Material NPM module?如何制作主题化的 Angular Material NPM 模块?
【发布时间】:2018-07-03 19:08:58
【问题描述】:

是否可以构建一个使用 Angular Material 的 npm 模块并允许它定义的组件由消费应用的自定义主题设置样式?

例如,假设我创建了一个 npm 模块,其中包含具有以下模板的组件:

<button mat-raised-button color="accent">Click me!</button>

是否可以将此组件导入两个不同的应用程序,每个应用程序都定义a custom Angular Material theme,并让按钮呈现当前应用程序主题的“重音”颜色?

目前,我正在使用 ng-packagr 构建对 Angular 友好的 npm 模块。然而,据我所知,这个模块包含一个.scss 编译阶段作为打包过程的一部分,这意味着模块中定义的任何样式都无法通过使用该模块的应用程序中的主题进行自定义。

【问题讨论】:

  • 我已经使用库组件进行材料主题化。有一篇博客文章 here 详细说明了如何做到这一点(以及代码示例)。

标签: javascript angular npm angular-material angular-material2


【解决方案1】:

Angular Material Theming Your Own Components 指南部分涵盖了有关如何执行此操作的要点。除了主题化你的组件之外,你的库(“npm 模块”)还需要为它自己的所有样式提供一个入口点,就像 Angular Material 库通过其angular-material-theme() mixin 所做的那样。这通常通过定义一个 mixin 来定义样式并调用所有组件主题 mixin 来完成,而不是创建一个带有样式定义的样式表文件。 mixin 将主题作为参数,并使用该主题来定义其自己的所有样式以及将主题应用于其任何组件。例如,您的库可能有自己的 _theme.scss 文件,任何消费应用程序都可以导入该文件,这将定义 mixin:

@import '~@angular/material/theming';
@import './components/my-component/_my-component-theme'; // component theming file with mixin
@mixin library-theme($theme) {

    @include angular-material-theme($theme); // angular material

    @include my-component-theme($theme); // component theming

    // define non-component styles
}

消费应用程序需要导入库的主题文件,创建自己的主题,然后调用库的主题 mixin。

显然还有更多细节,但这些是基础。作为参考,我建议您通过 GitHub 查看 Angular Material 是如何实现自己的 theming 的。

【讨论】:

    【解决方案2】:

    确实有可能。这个问题与 Angular 无关,它适用于任何其他框架。

    在此之前,您需要了解依赖倒置的概念。假设您正在构建您的应用程序 App1App2 并使用包含可重用组件的 npm 模块 lib。您的应用构建在 lib 之上,这意味着您的应用是更高级别的模块,而 lib 是较低级别的模块。

    如果您认为您的 lib 是独立的,那么理想情况下,它的性能应该与在 App1App2 中使用的相同。但是您的要求是 - lib 应该根据应用程序具有不同的行为(在这种情况下为样式)。这意味着您希望更高级别的模块对较低级别的模块应该如何表现做出一些决定。所以你正在反转依赖,这就是依赖反转原则。阅读有关DIP on wikipedia 的更多信息。

    现在要实现 DIP,您需要从库中公开某种端口/扩展,并且出于样式目的,最简单的方法是公开 SCSS mixins。但是,如果您使用任何构建工具,如 Webpack、rollup 或 ng-package,那么它们将始终生成已编译的发行版。您将不得不编写一些额外的 node.js 脚本来打包您的源代码(此处为 SCSS)以及已编译的代码。这些脚本将在编译/捆绑步骤中执行。

    在我的工作中,我有类似的要求。您应该遵循一些准则:

    1. 库中的组件应该使用一些默认样式开箱即用。
    2. 默认情况下,库的用户不必每次都自定义组件。
    3. 为样式公开组件中的 mixin。
    4. 在 mixins 中,不要放置任何硬编码的首选项。
    5. 开发主题化组件时,从默认开始。覆盖应用程序中组件使用的默认 CSS 类。将公共自定义点/属性粉笔掉,然后将其放回库的下一个版本。不要在库中进行前期开发。这通常会导致返工。

    我们有企业级应用。总共有 5 个不同的应用程序和一个私有发布的 npm 模块,为所有这五个应用程序提供公共组件。但是有些组件需要不同的样式,正如我所说,首先在我们的应用程序中覆盖类,然后一旦感觉通用到足以放入通用模块中,我们就会将其放入下一个版本中。

    【讨论】:

    • 我非常不同意这一点Components from a library should work out of the box with some default styling。使用angular-material 需要在应用级别指定主题(如果不这样做,材质元素将不会显示任何 css);因此,如果有应用程序级别的要求,为什么还要在 lib 级别强制使用默认值?再加上这些价值观可能毫无意义;大多数情况下,您想要访问primaryaccentwarn 颜色,只有在它们反映当前应用程序主题值而不是随机默认值时才能进行语义。
    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 2017-10-29
    • 2022-12-11
    相关资源
    最近更新 更多