Angular2 动态更改 CSS 属性

73
我们正在开发一个Angular2应用程序,希望能够创建全局CSS变量,并在将变量分配给属性时随时更新属性值。我们曾经使用过Polymer一段时间(现在正在切换到Angular2组件),并使用了CSS属性(Polymer有一些polyfill),我们只需使用Polymer.updateStyles()更新样式即可。
是否有任何方法可以实现类似的功能?
编辑:
我们想要类似于Sass color: $g-main-color或CSS自定义属性color: var(--g-main-color)的功能,每当我们决定更改属性值(例如updateVariable('g-main-color','#112a4f'))时,它将动态地更新所有已分配该变量的位置的值,同时应用程序正在运行。
编辑2:
我希望在我的CSS的不同部分(宿主、子元素...)中使用一些全局CSS变量,并且能够立即更改值-因此,如果我更改了my-color变量,则会在整个应用程序中都会更改。
我将使用Sass语法作为示例:
:host { border: 2px solid $my-color }
:host .some-label { color: $my-color }

是否可能使用类似Angular管道的东西?(但它据说只在HTML中起作用)

:host { border: 2px solid {{ 'my-color' | cssvariable }} }
:host .some-label { color: {{ 'my-color' | cssvariable }} }

3
我很想知道你采用了什么方法。我们有类似的要求。 - Yousuf
我仍然没有解决这个问题。唯一合理的方法可能是使用带有某种polyfill的CSS变量... - tenhobi
你知道在Angular2中有哪些polyfill可以用来替换变量吗? - Yousuf
绑定ngStyle到对象时无法工作,是否有原因?这些对象可以来自任何地方,并且您可以在运行时随意更改它们。这样,您就不必提前知道属性或值,只需构造一个对象,将其分配给元素绑定的值,然后更改即可。这意味着您可以将任何类型的预制、静态或编译的CSS排除在外。如果这不好用,您始终可以将所有元素绑定到innerHTML,并通过应用样式的span动态创建来更改innerHTML。 - Tim Consolazio
你可以使用管道:https://dev59.com/GLbna4cB1Zd3GeqPgL4f#66244720 - adrisons
5个回答

71

1) 使用内联样式

<div [style.color]="myDynamicColor">

2) 使用多个CSS类映射到你想要的样式,然后像下面这样切换类:

 /* CSS */
 .theme { /* any shared styles */ }
 .theme.blue { color: blue; }
 .theme.red { color: red; }

 /* Template */
 <div class="theme" [ngClass]="{blue: isBlue, red: isRed}">
 <div class="theme" [class.blue]="isBlue">

代码示例来自:https://angular.io/cheatsheet

有关ngClass指令的更多信息: https://angular.io/docs/ts/latest/api/common/index/NgClass-directive.html


2
这可能有效,但有一个问题 - 你必须将动态样式与CSS文件分开,这从来不是最好的方式。 :( 我更希望在CSS中有一些东西,但我可能不得不处理它。 - tenhobi
我不明白。使用SASS/LESS。对于来自JavaScript的动态样式,我只能看到那些。无论如何,除非你做错了,否则不能混合静态和动态样式。静态:CSS。动态:JavaScript。 - Gerard Sans
我曾经说过,如果能够像Angular2的管道一样在CSS文件或区域内编写代码就好了。但这可能是不可能的,所以我将不得不像你在1)中所写的那样,并且可能只需在Sass文件中添加注释,说明使用(或应该使用)来自外部的全局变量。 - tenhobi
如果你感到有冒险精神,你可以构建一个步骤来采用SASS,并输出一个JS模块,以便您可以导入 ^_^ - Gerard Sans
不适用于带有数字的变量,您不想创建10000个类。 - Milad

25

只需使用标准的CSS变量:

您的全局CSS文件(例如:styles.css)

body {
  --my-var: #000
}

在你的组件的 CSS 中或者其他相关文件中:

span {
  color: var(--my-var)
}

然后你可以通过将内联样式设置为 HTML 元素,使用 TS/JS 直接更改变量的值:

document.querySelector("body").style.cssText = "--my-var: #000";
否则,您可以使用jQuery来实现它:
$("body").css("--my-var", "#fff");

4
这正是我想要的,谢谢你分享这个。 - Noopur Dabhi
在使用Angular 2.0+时,直接操作DOM和jQuery不是最后的选择吗? - Giant Elk
看看这个,来自Angular文档的Renderer2:https://angular.io/api/core/Renderer2 - Giant Elk
@GiantElk 对的,但我只是在改变CSS变量的值。由于ngStyle不支持绑定CSS变量,我认为这实际上是最简单的解决方案。个人而言,我永远不会使用像Renderer这样复杂的API来改变变量的值。 - raythurnevoid
如何使用多个变量?我不使用jQuery($)。 - Sahi

5

您没有任何示例代码,但我想您希望做类似于这样的事情吗?

@View({
directives: [NgClass],
styles: [`
    .${TodoModel.COMPLETED}  {
        text-decoration: line-through;
    }
    .${TodoModel.STARTED} {
        color: green;
    }
`],
template: `<div>
                <span [ng-class]="todo.status" >{{todo.title}}</span>
                <button (click)="todo.toggle()" >Toggle status</button>
            </div>`
})

你将ng-class分配给一个动态变量(可以猜到是模型中称为TodoModel的属性)。 todo.toggle()会更改todo.status的值,因此输入框的类也会随之更改。
这只是类名的示例,实际上你也可以对css属性做同样的操作。
希望这就是你所需要的内容。
这个例子来自于优秀的egghead教程,在此处

5
这不是我们想要的。我们想要像 Sass 中的 color: $g-main-color 或者 CSS 自定义属性中的 color: var(--g-main-color) 这样的东西,并且每当我们决定更改属性的值时,比如使用 JS 中的 updateVariable('g-main-color', '#112a4f'),它会动态地更新所有地方的值,而应用程序仍在运行。 - tenhobi

2
我做了一个这个plunker来探索你想要的一种方法。
在此,我从父组件中获取mystyle,但您也可以从服务中获取它。
import {Component, View} from 'angular2/angular2'

@Component({
  selector: '[my-person]',
  inputs: [
    'name',
    'mystyle: customstyle'
  ],
  host: {
    '[style.backgroundColor]': 'mystyle.backgroundColor'
  }
})
@View({
  template: `My Person Component: {{ name }}`
})
export class Person {}

我必须能够更改主机和子元素的样式,但您的解决方案无法实现,而且从“CSS区域”外部编写样式有点混乱。请看编辑2。顺便说一句,与其通过属性从输入中获取颜色,不如只导入某个类并使用其中的变量,因为我想要整个应用程序的全局变量。;) - tenhobi

-1

Angular 6 + Alyle UI

使用Alyle UI,您可以动态更改样式。

这里有一个演示 stackblitz

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    CommonModule,
    FormsModule,
    HttpClientModule,
    BrowserAnimationsModule,
    AlyleUIModule.forRoot(
      {
        name: 'myTheme',
        primary: {
          default: '#00bcd4'
        },
        accent: {
          default: '#ff4081'
        },
        scheme: 'myCustomScheme', // myCustomScheme from colorSchemes
        lightGreen: '#8bc34a',
        colorSchemes: {
          light: {
            myColor: 'teal',
          },
          dark: {
            myColor: '#FF923D'
          },
          myCustomScheme: {
            background: {
              primary: '#dde4e6',
            },
            text: {
              default: '#fff'
            },
            myColor: '#C362FF'
          }
        }
      }
    ),
    LyCommonModule, // for bg, color, raised and others
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

HTML

<div [className]="classes.card">dynamic style</div>
<p color="myColor">myColor</p>
<p bg="myColor">myColor</p>

更改样式

import { Component } from '@angular/core';
import { LyTheme } from '@alyle/ui';

@Component({ ... })
export class AppComponent  {
  classes = {
    card: this.theme.setStyle(
      'card', // key
      () => (
        // style
        `background-color: ${this.theme.palette.myColor};` +
        `position: relative;` +
        `margin: 1em;` +
        `text-align: center;`
         ...
      )
    )
  }
  constructor(
    public theme: LyTheme
  ) { }

  changeScheme() {
    const scheme = this.theme.palette.scheme === 'light' ?
    'dark' : this.theme.palette.scheme === 'dark' ?
    'myCustomScheme' : 'light';
    this.theme.setScheme(scheme);
  }
}

Github代码库


这个问题是关于Dart的。我猜这行不通。 - Günter Zöchbauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接