【问题标题】:Angular Material themes toggle not switching themesAngular Material 主题切换不切换主题
【发布时间】:2021-04-26 15:16:58
【问题描述】:

场景
我们遵循此tutorial 为我们的用户提供深色和浅色主题。

问题
浏览器加载预期的 css 文件(深色或浅色)。然而,这些样式并没有应用于我们的组件。 这发生在<head></head>

<link rel="stylesheet" type="text/css" href="theme-dark.css">

<link rel="stylesheet" type="text/css" href="theme-light.css">

如您所见,浏览器正确切换了两个主题。

代码
angular.json

"styles": [
          "projects/menu/src/styles.scss",
          {
            "input": "projects/menu/src/theming/theme-dark.scss",
            "bundleName": "theme-dark",
            "inject": false
          },
          {
            "input": "projects/menu/src/theming/theme-light.scss",
            "bundleName": "theme-light",
            "inject": false
          }
        ],

theme-service.ts

private _mainTheme$: BehaviorSubject<string> = new BehaviorSubject(
    'theme-light'
);
private _darkMode$: BehaviorSubject<boolean> = new BehaviorSubject(false);

darkMode$: Observable<boolean> = this._darkMode$.asObservable();

private _renderer: Renderer2;
private head: HTMLElement;
private themeLinks: HTMLElement[] = [];

theme$: Observable<[string, boolean]>;

constructor(
    rendererFactory: RendererFactory2,
    @Inject(DOCUMENT) document: Document
) {
    this.head = document.head;
    this._renderer = rendererFactory.createRenderer(null, null);
    this.theme$ = combineLatest([this._mainTheme$, this._darkMode$]);
    this.theme$.subscribe(async ([mainTheme, darkMode]) => {
        const cssExt = '.css';
        const cssFilename = darkMode
            ? 'theme-dark' + cssExt
            : mainTheme + cssExt;
        await this.loadCss(cssFilename);
        if (this.themeLinks.length == 2)
            this._renderer.removeChild(this.head, this.themeLinks.shift());
    });
}

setMainTheme(name: string) {
    this._mainTheme$.next(name);
}

setDarkMode(value: boolean) {
    this._darkMode$.next(value);
}

private async loadCss(filename: string) {
    return new Promise((resolve) => {
        const linkEl: HTMLElement = this._renderer.createElement('link');
        this._renderer.setAttribute(linkEl, 'rel', 'stylesheet');
        this._renderer.setAttribute(linkEl, 'type', 'text/css');
        this._renderer.setAttribute(linkEl, 'href', filename);
        this._renderer.setProperty(linkEl, 'onload', resolve);
        this._renderer.appendChild(this.head, linkEl);
        this.themeLinks = [...this.themeLinks, linkEl];
    });
}

theme-base.scss

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

@include mat-core();

@mixin theming($theme) {
  @include angular-material-theme($theme);
}

theme-dark.scss

@import '~@angular/material/theming';
@import './theme-base';

@include mat-core();

// color palette definitions

$primary: mat-palette($dark-md-mcgpaletteblack);
$accent: mat-palette($md-mcgpalettewhite);
$warn: mat-palette($dark-md-mcgpalettered);
$background:mat-palette($dark-md-mcgpalettebackground);
$confirm: mat-palette($dark-md-mcgpaletteorange);

$theme-dark: mat-dark-theme((color: (primary: $primary,
  accent: $accent,
  warn: $warn,
  background: $background,
  confirm: $confirm)));

theme-dark.scss - 看起来一样

style.scss 中我们导入了两个主题:

styles.scss

@import 'projects/menu/src/theming/theme-dark.scss';
@import 'projects/menu/src/theming/theme-light.scss';

.theme-dark {
  @include angular-material-theme($theme-dark)
}

.theme-light {
  @include angular-material-theme($theme-light)
}

然后我们使用这些变量:

styles.scss

body {
  background: mat-color($background, default);
}

h1 {
   color: mat-color($accent, default);
}

但目前我们也将它们导入到我们的组件中。我认为这是一回事,那是错误的。
对话框如下所示:

@import 'projects/menu/src/theming/theme-dark.scss';
@import 'projects/menu/src/theming/theme-light.scss';

.theme-dark {
  @include angular-material-theme($theme-dark)
}

.theme-light{
  @include angular-material-theme($theme-light)
}

.mat-button {
  color: mat-color($accent, default);
  background-color: mat-color($confirm, default);
}

我尝试了什么:

  • 删除每个样式表中两个主题的导入。颜色仍然受style.scss 中主题导入顺序的影响。最后使用深色主题 -> 将使用深色主题,反之亦然。
  • 对主题使用与教程中相同的变量。但后来我们不得不改变所有的background-color: mat-color($confirm, default);
  • 等等。花了很多时间...

我们无法弄清楚如何将缺少的部分组合在一起。我们需要使用mixins吗?还是我们缺少在根组件上设置 dark-theme 类?

非常感谢您。

【问题讨论】:

    标签: css angular sass angular-material themes


    【解决方案1】:

    我们终于让它工作了。

    我们的错误:

    • @include mat-core(); 只能导入一次(在theme-base.scss 中)
    • @import 'projects/menu/src/theming/theme-dark.scss';@import 'projects/menu/src/theming/theme-light.scss'; 只能导入一次(在 styles.scss 中)。在所有组件中导入它们会使包的大小爆炸式增长。
    • 直接在theme-dark.scss中设置theme-dark
    • 不要在styles.scss 或任何其他组件主题中设置类theme-darktheme-light
    • 为整个应用程序创建两个包装器元素:&lt;div [ngClass]="{ 'theme-dark': darkMode$ | async }"&gt; &lt;div class="mat-app-background"&gt; &lt;router-outlet&gt;&lt;/router-outlet&gt;&lt;/div&gt;&lt;/div&gt;
    • 如果组件需要访问主题,请使用 mixins(示例如下)
    • theme-service.ts 中,使用OverlayContainer 将样式也应用于材质对话框(如here 所述)

    混音示例:

    settings-dialog.component.scss

    @import '~@angular/material/theming';
    
    @mixin settings-dialog-theme($theme) {
      .settings-dialog {
        @include mat-elevation(2);
        .mat-button {
          background-color: mat-color($confirm);
        }
      }
    }
    

    settings-dialog.component.html

    <div mat-dialog-content class="settings-dialog"> Put your content here </div>
    

    按照here 的描述创建组件主题
    component-themes.scss

    @import 'your-path/settings-dialog.component';
    @mixin component-themes($theme) {
      @include settings-dialog-theme($theme);
    }
    

    将其导入您的基本主题文件
    theme-base.scss

    @import '~@angular/material/theming';
    @import './component-themes.scss';
    
    @include mat-core();
    
    @mixin theming($theme) {
        @include angular-material-theme($theme);
        @include component-themes($theme);
    }
    

    【讨论】:

      猜你喜欢
      • 2021-08-12
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2022-09-30
      • 2020-10-30
      • 2014-11-23
      • 2018-01-04
      • 1970-01-01
      相关资源
      最近更新 更多