尝试根据 angular material 动态延迟加载自定义主题

Trying to lazy load custom themes dynamically based on angular material

我正在用 angular material 编写一个 angular 12 网站。 该项目支持多个域,在不同的域上它应该显示不同的主题。

所以我在这里要解决的问题是能够通过延迟加载动态加载主题。

我的自定义主题有效..基本 angular material 功能无效,但我确实收到消息

Could not find Angular Material core theme. Most Material components may not work as expected. For more info refer to the theming guide: https://material.angular.io/guide/theming

我用谷歌搜索了很多,如果我正确加载 css 文件并将其附加到头部,它应该可以正常工作。

好的..所以首先..

我创建了 app/themes 目录

我有 3 个主题,windy.scsswindy-car.scsswindy-shop.scss,每个主题都需要 common.scss

我有几个组件使用我在每个文件中创建的具有特定颜色的变量,并且 common.scss 实际上在选择颜色时装饰组件。

例如:

common.js 包括:

app-root {

  div#my-mat-drawer {
    background: $container-bg;
  }

}

windy.scss包含:

$container-bg:  #aabbcc;

我将展示一个 scss 文件作为示例,当我只使用一个主题时它起作用了,所以我知道格式很好。

这是windy.scss:

@use '../../node_modules/@angular/material/index' as mat;
$container-bg:  #aabbcc;
$container-color:  white;

$button1-color: #ccdd99;
$button2-color: #112233;

$product-card-text: red;

$category-title-bg: blue;

$product-categories-bg: yellow;

$toolbar-bg-color: green;

$dark-primary-text: rgba(black, 0.87);
$dark-secondary-text: rgba(black, 0.54);
$dark-disabled-text: rgba(black, 0.38);
$dark-dividers: rgba(black, 0.12);
$dark-focused: rgba(black, 0.12);
$light-primary-text: white;
$light-secondary-text: rgba(white, 0.7);
$light-disabled-text: rgba(white, 0.5);
$light-dividers: rgba(white, 0.12);
$light-focused: rgba(white, 0.12);

$my-cyan-palette: (
  50: #e0f7fa,
  100: #b2ebf2,
  200: #80deea,
  300: #4dd0e1,
  400: #26c6da,
  500: #00bcd4,
  600: #00acc1,
  700: #0097a7,
  800: #00838f,
  900: $button2-color,
  A100: #84ffff,
  A200: #18ffff,
  A400: #00e5ff,
  A700: #00b8d4,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $dark-primary-text,
    400: $dark-primary-text,
    500: $light-primary-text,
    600: $light-primary-text,
    700: $light-primary-text,
    800: $light-primary-text,
    900: $light-primary-text,
    A100: $dark-primary-text,
    A200: $dark-primary-text,
    A400: $dark-primary-text,
    A700: $dark-primary-text,
  )
);

$my-lime-palette: (
  50: #f9fbe7,
  100: #f0f4c3,
  200: #e6ee9c,
  300: #dce775,
  400: #d4e157,
  500: #cddc39,
  600: #c0ca33,
  700: #afb42b,
  800: #9e9d24,
  900: $button1-color,
  A100: #f4ff81,
  A200: #eeff41,
  A400: #c6ff00,
  A700: #aeea00,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $dark-primary-text,
    400: $dark-primary-text,
    500: $dark-primary-text,
    600: $dark-primary-text,
    700: $dark-primary-text,
    800: $dark-primary-text,
    900: $light-primary-text,
    A100: $dark-primary-text,
    A200: $dark-primary-text,
    A400: $dark-primary-text,
    A700: $dark-primary-text,
  )
);



$windy-store-primary: mat.define-palette($my-cyan-palette, 900);
$windy-store-accent: mat.define-palette($my-lime-palette,900); 
$windy-store-warn: mat.define-palette($my-cyan-palette,900);

 $windy-store-theme: mat.define-light-theme((
  color: (
    primary: $windy-store-primary,
    accent: $windy-store-accent,
    warn: $windy-store-warn,
  )
));

@include mat.all-component-themes($windy-store-theme);
@import "common";

现在..在angular.json中我添加了这些文件 inject: false:

"styles": [
              "src/styles.scss",
              {
                "input": "src/themes/windy.scss",
                "bundleName": "windy",
                "inject": false
              },
              {
                "input": "src/themes/windy-car.scss",
                "bundleName": "windy-car",
                "inject": false
              },
              {
                "input": "src/themes/windy-shop.scss",
                "bundleName": "windy-shop",
                "inject": false
              }
            ]

我创建了一个样式管理器服务和一个 theme.service 并将它们添加到 app.module.ts 中的提供程序。

样式管理器-service.ts

/**
 * Copied from https://github.com/angular/material.angular.io/blob/master/src/app/shared/style-manager/style-manager.ts
 */

import { Injectable } from "@angular/core";

@Injectable()
export class StyleManagerService {
  constructor() {}

  /**
   * Set the stylesheet with the specified key.
   */
  setStyle(key: string, href: string) {
    getLinkElementForKey(key).setAttribute("href", href);
  }

  /**
   * Remove the stylesheet with the specified key.
   */
  removeStyle(key: string) {
    const existingLinkElement = getExistingLinkElementByKey(key);
    if (existingLinkElement) {
      document.head.removeChild(existingLinkElement);
    }
  }
}

function getLinkElementForKey(key: string) {
  return getExistingLinkElementByKey(key) || createLinkElementWithKey(key);
}

function getExistingLinkElementByKey(key: string) {
  return document.head.querySelector(
    `link[rel="stylesheet"].${getClassNameForKey(key)}`
  );
}

function createLinkElementWithKey(key: string) {
  const linkEl = document.createElement("link");
  linkEl.setAttribute("rel", "stylesheet");
  linkEl.setAttribute("type", "text/css");
  linkEl.classList.add(getClassNameForKey(key));
  document.head.appendChild(linkEl);
  return linkEl;
}

function getClassNameForKey(key: string) {
  return `app-${key}`;
}

theme.service.ts

import { Injectable } from "@angular/core";

import { StyleManagerService } from "./style-manager.service";

@Injectable()
export class ThemeService {
  constructor(
    private styleManager: StyleManagerService
  ) {}


  setTheme(themeToSet: string) {
    this.styleManager.setStyle(
      "theme",
      `${themeToSet}.css`
    );
  }
}

并且我在 app.component.ts 中注入了 private readonly themeService: ThemeService 并且在构造函数中注入了 运行 this.themeService.setTheme('windy-car');

和结果.. 我确实看到了所选主题的自定义颜色,但是 angular material 功能被破坏了。 color=primary 不起作用,angular material 的其他相关样式不显示。

例如在工具栏中我有 color="primary" 但颜色仍然是白色。

我确定这与错误 Could not find Angular Material core theme. Most Material components may not work as expected. For more info refer to the theming guide: https://material.angular.io/guide/theming 有关,但我不知道如何解决这个问题。

有什么想法吗?

** 更新 1 **

当我在 styles.scss 中添加以下内容时:

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

@include mat-core();

我仍然得到错误

Could not find Angular Material core theme. Most Material components may not work as expected. For more info refer to the theming guide: https://material.angular.io/guide/theming

angular material 组件工作正常,但它完全忽略了我选择的颜色。

我终于解决了:)

所以在主 style.scss 文件中我添加了:

@use '~@angular/material' as mat;
@import '~@angular/material/theming';
@include mat.core();

我还添加了一个默认主题,我用我的文件覆盖它只是为了不出现错误“找不到 angular material 核心主题”

$a-primary: mat.define-palette(mat.$indigo-palette);
$a-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

// The warn palette is optional (defaults to red).
$a-warn: mat.define-palette(mat.$red-palette);

// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$a-theme: mat.define-light-theme((
  color: (
    primary: $a-primary,
    accent: $a-accent,
    warn: $a-warn,
  )
));

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include mat.all-component-themes($a-theme);

  • 更新- 我实际上删除了它。我瞬间看到了我定义的这个主题,然后它变成了我的延迟加载主题。如果我愿意,我可以将这个主题更改为 write,这样开关就不会那么糟糕了。但是我完全删除了它,除了有这个警告之外它不会以任何方式影响我的应用程序。

在我的个人主题样式文件中,我只需要 @use '../../node_modules/@angular/material/index' as mat;

现在在公共 scss 中而不是直接指向我的组件,我创建了一个 class 并将该 class 名称添加到组件。

例如:

而不是:

app-toolbar {
  mat-toolbar {
    background: $toolbar-bg-color;
  }
}

原来我有很多 ::ng-deep 但我把它们都删除了,因为我想修改的所有组件都有 panelClass 属性 和我的组件..我只是给了他们改用 class 名字。

所以我刚刚做了:

.app-toolbar-mat-toolbar {
    background: $toolbar-bg-color;
  }