您可以将 Angular 主题原色应用于 div 吗?

Can you apply an Angular themes primary color to a div?

有没有办法为 Angular 7 应用程序设置主题,以便您可以:

例如

我想做这样的事情:

<div color="primary">

</div>

但这不起作用,因为 color 属性仅适用于 angular material 个组件。

此外,我希望能够根据当前主题更改背景颜色、文本颜色等。 (深色主题、浅色主题)

关于解决方案

使用此解决方案,您可以:

  • 运行时切换主题
  • 运行时获取当前主题
  • 主题直接在 CSS 中而不使用额外的 classes 或任何东西
  • 有一个易于使用且易于理解的解决方案,只需要一次性设置

缺点:

  • 使用 CSS 个变量。一些较旧的浏览器可能不支持它们
  • 依赖更新的 Angular 版本。我不知道这是否适用于旧版本(在 Angular 6 和 7 中测试)

这是我现在在我的项目中使用的:

设置

首先你需要定义一个主题。

这是一个名为 dark-theme.scss 的示例,位于 src/themes:

@import '~@angular/material/theming';
@include mat-core();

// Set variables to whatever colors you want for your app
$dark-theme-primary: mat-palette($mat-pink);
$dark-theme-accent: mat-palette($mat-light-blue);
$dark-theme-warn: mat-palette($mat-red);

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

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

那么你需要一个可以创建主题SCSS和CSS变量的SCSS函数:

这是我的 functions.scsssrc/assets/scss:

@mixin generate-theme-vars($theme) {
  //default palette foreground/background:
  $foreground-palette: map-get($theme, foreground);
  $background-palette: map-get($theme, background);

  /////////////////////////////////////////////////
  // SCSS VARS
  /////////////////////////////////////////////////

  $primary: mat-color(map-get($theme, primary));
  $accent: mat-color(map-get($theme, accent));
  $warn: mat-color(map-get($theme, warn));

  $base: mat-color($foreground-palette, base);
  $divider: mat-color($foreground-palette, divider);
  $dividers: mat-color($foreground-palette, dividers);
  $disabled: mat-color($foreground-palette, disabled);
  $disabled-button: mat-color($foreground-palette, disabled-button);
  $disabled-text: mat-color($foreground-palette, disabled-text);
  $hint-text: mat-color($foreground-palette, hint-text);
  $secondary-text: mat-color($foreground-palette, secondary-text);
  $icon: mat-color($foreground-palette, icon);
  $icons: mat-color($foreground-palette, icons);
  $text: mat-color($foreground-palette, text);
  $slider-off: mat-color($foreground-palette, slider-off);
  $slider-off-active: mat-color($foreground-palette, slider-off-active);
  
  $status-bar: mat-color($background-palette, status-bar);
  $app-bar: mat-color($background-palette, app-bar);
  $background: mat-color($background-palette, background);
  $hover: mat-color($background-palette, hover);
  $card: mat-color($background-palette, card);
  $dialog: mat-color($background-palette, dialog);
  $disabled-button: mat-color($background-palette, disabled-button);
  $raised-button: mat-color($background-palette, raised-button);
  $focused-button: mat-color($background-palette, focused-button);
  $selected-button: mat-color($background-palette, selected-button);
  $selected-disabled-button: mat-color($background-palette, selected-disabled-button);
  $disabled-button-toggle: mat-color($background-palette, disabled-button-toggle);

  /////////////////////////////////////////////////
  // CSS VARS
  /////////////////////////////////////////////////


  --primary-color: #{$primary};
  --accent-color: #{$accent};
  --warn-color: #{$warn};

  --base-color: #{$base};
  --divider-color: #{$divider};
  --dividers-color: #{$dividers};
  --disabled-color: #{$disabled};
  --disabled-text-color: #{$disabled-text};
  --hint-text-color: #{$hint-text};
  --secondary-text-color: #{$secondary-text};
  --icon-color: #{$icon};
  --icons-color: #{$icons};
  --text-color: #{$text};
  --slider-off-color: #{$slider-off};
  --slider-off-active-color: #{$slider-off-active};

  --status-bar-color: #{$status-bar};
  --app-bar-color: #{$app-bar};
  --background-color: #{$background};
  --hover-color: #{$hover};
  --card-color: #{$card};
  --dialog-color: #{$dialog};
  --disabled-button-color: #{$disabled-button};
  --raised-button-color: #{$raised-button};
  --focused-button-color: #{$focused-button};
  --selected-button-color: #{$selected-button};
  --selected-disabled-button-color: #{$selected-disabled-button};
  --disabled-button-toggle-color: #{$disabled-button-toggle};
}

之后,一切就绪,您只需为全局 styles.scss:

中的每个主题创建一个 class
@import "functions";
@import "~@angular/material/theming";

// You have to define one of those for every theme you offer
.dark-theme {
    @import "themes/dark-theme";
    @include angular-material-theme($dark-theme);
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

用法

要应用您要使用的主题,您需要将 CSS class dark-theme(或任何您称呼它的东西)放在一个包含所有其他元素的元素中。

我把它放到HTML标签:

<!doctype html>
<html lang="en" class="dark-theme">
    <!-- ... -->
</html>

现在您可以在运行时切换主题,例如将 class 和 JavaScript 更改为 light-theme

在每一个 CSS 属性 想要颜色的地方,你现在可以使用变量:

div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    .someText {
        color: var(--text-color);
    }
}

如果你想在你的 CSS 中做一些事情,如果应用了一个特殊的主题并且改变的不是颜色本身,那么这样做:

// Example: We want to remove some div only when the light-theme is used
div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    
    :host-context(.light-theme) & {
        display: none;
    }
}

PS

对于可能想知道为什么我使用 @import "functions"; 的每个人,即使它们位于不同的文件夹中:

进入 angular.json 并向对象 projects > <YourProject> > architect > build > options 添加以下内容:

"stylePreprocessorOptions": {
    "includePaths": [
    "src/assets/scss"
    ]
},

现在您可以从每个路径使用 @import "functions";

如果您需要支持 IE(未经测试,可能需要改进)

因此,如果您不能在某些客户端上使用 CSS 变量,您可以像这样为指定的颜色定义回退:

div {
    background-color: red; // fallback to red if the variable doesnt exist -> Old browsers, or IE
    background-color: var(--app-bar-color);
}

有了这些知识,您可以在 styles.scss:

中定义一些 SCSS 变量
@import "functions";
@import "~@angular/material/theming";

// Default theme
@import "themes/dark-theme";
@include angular-material-theme($dark-theme);

// Generate SCSS vars
$foreground-palette: map-get($theme, foreground);
$background-palette: map-get($theme, background);

/////////////////////////////////////////////////
// SCSS VARS
/////////////////////////////////////////////////

$primary: mat-color(map-get($theme, primary));
$accent: mat-color(map-get($theme, accent));
$warn: mat-color(map-get($theme, warn));

// ... and all the other vars from above if you would like


// You have to define one of those for every theme you offer
.dark-theme {
    // Only init the CSS vars here, because the rest is in default
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

现在你可以像这样使用它了:

div {
    background-color: $primary; // fallback
    background-color: var(--primary-color);
}

This cant be changed dynamically with JS during the runtime anymore though!!

对于可能出现错误的人 - SassError: Undefined variable.,如果您尝试使用 @mixin generate-theme-vars($theme) 下定义的任何变量,则需要在这些变量中添加 !global .例如定义: $base: mat-color($foreground-palette, base) !global;

这将使变量成为全局变量,您可以在任何地方使用它。