Angular Material - 黑暗模式改变背景图片

Angular Material - Dark Mode Changing Background Image

目前我有一个应用程序组件,它有一个 sidenav 和我的 router-outlet 在 sidenav 内容中。在此组件中,我通过在 style.scss.

中添加或删除 darkMode class 来管理应用程序主题

有没有办法控制我使用的背景图像?

如果我还想根据 router-outlet 上打开的组件来控制背景图片怎么办?那有可能吗?也许不在应用程序组件中设置背景图像,而是在打开的组件中设置

app.component.html

<mat-sidenav-container autosize class="h-100">
    <mat-sidenav #sidenav mode="side" opened="true">
        <mat-nav-list>
            <mat-list-item>
                <mat-slide-toggle [formControl]="toggleControl"></mat-slide-toggle>
            </mat-list-item>
            ...
        <mat-sidenav-content>
            <router-outlet></router-outlet>
        </mat-sidenav-content>

app.component.ts

@HostBinding('class') className = '';
toggleControl = new FormControl(false);

constructor(private overlay: OverlayContainer, ...) { }

ngOnInit() {
    this.toggleControl.valueChanges.subscribe((darkMode) => {
      const darkClassName = 'darkMode';
      this.className = darkMode ? darkClassName : '';
      if (darkMode) {
        this.overlay.getContainerElement().classList.add(darkClassName);
      } else {
        this.overlay.getContainerElement().classList.remove(darkClassName);
      }
    });

    this.subscription = this._service.currentLogStatus.subscribe(logStatus => this.loggedIn = logStatus);
}

app.component.scss

mat-sidenav-container {
    background-image: url('../assets/img/home-background.png');
}

style.scss

.darkMode {
  @include mat.all-component-colors($angular-dark-theme);
}

更新

在我尝试了一些迹​​象之后。

darkMode 背景仍然存在于 ProfileComponent 上,即使我引用了另一个背景。

app.component.html

<mat-sidenav-content>
        <router-outlet (activate)="onRouterOutletActivate($event)"></router-outlet>
</mat-sidenav-content>

app.component.ts

ngOnInit() {
    this.toggleControl.valueChanges.subscribe((toggled) => {
      console.log(this.currentComponent);
      this.className = toggled ? 'darkMode' : '';
      
      if (toggled) {
        if (this.currentComponent == "home") {
          this._overlay.getContainerElement().classList.add('darkMode');
          this._overlay.getContainerElement().classList.remove('darkModeProfile');
        }

        if (this.currentComponent == "profile") {
          this._overlay.getContainerElement().classList.add('darkModeProfile');
          this._overlay.getContainerElement().classList.remove('darkMode');
        }
      } else {
        if (this.currentComponent == "home") {
          this._overlay.getContainerElement().classList.remove('darkMode');
        }

        if (this.currentComponent == "profile") {
          this._overlay.getContainerElement().classList.remove('darkModeProfile');
        }
      }
    });

    this.subscription = this._service.currentLogStatus.subscribe(logStatus => this.loggedIn = logStatus);
  }

  public onRouterOutletActivate(event : any) {
    if (event.constructor.name == "ProfileComponent") {
      this.currentComponent = "profile";
    }

    if (event.constructor.name == "HomeComponent") {
      this.currentComponent = "home";
    }
  }

app.component.scss

mat-sidenav-container {
    background-image: url('../assets/img/home-background.png');
}

:host-context(.darkMode) {
    mat-sidenav-container {
        background-image: url('../assets/img/home-background-dark.png');
    }
}

:host-context(.darkModeProfile) {
    mat-sidenav-container {
        background-image: url('../assets/img/profile-background.png');
    }
}

What if I also wanted to control the background image based on what component is opened on the router-outlet?

您可能需要 RouterLinkActive 指令。

Tracks whether the linked route of an element is currently active, and allows you to specify one or more CSS classes to add to the element when the linked route is active.

如何使用?

<a routerLink="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>

要仅在 URL 与 link 完全匹配时添加 类,请添加此选项 exact: true:

<a routerLink="/user/bob" routerLinkActive="active-link" [routerLinkActiveOptions]="{exact:
true}">Bob</a>

更多信息和示例可以在官方文档中找到。 https://angular.io/api/router/RouterLinkActive

更新:

要检测哪个组件被打开/激活,您可以使用 router-outlet.

的 (activate) 指令
<router-outlet (activate)='onActivate($event)'></router-outlet>

根据该逻辑,您可以更改打开的组件的背景。

带有(激活)指令的 Stackblitz https://stackblitz.com/edit/angular-router-basic-example-dvsmnx?file=app%2Fapp.component.ts

对我有用的解决方案是维护 .darkMode class 并根据 router-outlet

呈现的组件使用不同的背景

解决方案

app.component.html

<mat-sidenav-container [ngStyle]="{ 'background': 
    'linear-gradient( rgba(0, 0, 0,' + theme + '), rgba(0, 0, 0,' + theme + ')),'+ 
    'url(../assets/img/' + currentComponent + '-background' + '.png)'}"
    autosize class="h-100">
    <mat-sidenav #sidenav mode="side" opened="true">
        <mat-nav-list>
            <mat-list-item>
                <mat-slide-toggle [formControl]="toggleControl"></mat-slide-toggle>
            </mat-list-item>
            ...
        <mat-sidenav-content>
            <router-outlet (activate)="onRouterOutletActivate($event)"></router-outlet>
        </mat-sidenav-content>
    </mat-sidenav>
</mat-sidenav-container>

app.component.ts

currentComponent: string = "home";
theme: number = 0;

constructor(private _overlay: OverlayContainer) { }

ngOnInit() {
  this.toggleControl.valueChanges.subscribe((toggled) => {
    this.className = toggled ? 'darkMode' : '';
      
    if (toggled) {
      this._overlay.getContainerElement().classList.add('darkMode');
      this.theme = 0.5;
    } else {
      this._overlay.getContainerElement().classList.remove('darkMode');
      this.theme = 0;
    }
  });

  this.subscription = this._service.currentLogStatus.subscribe(logStatus => this.loggedIn = logStatus);
}

public onRouterOutletActivate(event : any) {
  if (event.constructor.name == "ProfileComponent" || event.constructor.name == "RegisterComponent") {
    this.currentComponent = "profile";
  }

  if (event.constructor.name == "HomeComponent") {
    this.currentComponent = "home";
  }
}

style.scss

.darkMode {
  @include mat.all-component-colors($angular-dark-theme);
}

这样做,我可以控制显示的图像并在 .darkMode 启用时应用滤镜。