Angular 2中的动态styleUrls是什么?

29

是否可能在组件中动态注入样式表的URL?

例如:

styleUrls: [
  'stylesheet1.css',
  this.additionalUrls
]

或者(一厢情愿的想法,注意这只是假代码):

export class MyComponent implements dynamicUrls {

  ngDynamicUrls() {
    this.inject(['anotherStylesheet.css', 'anotherStylesheet2.css']);
  }
}
因为如果你想要覆盖某些来自 stylesheet1 的样式,但又无法访问它,那么你该怎么做呢?我的唯一想法是以某种方式使用动态 styleUrls ,但我认为这甚至从我能找到的资料中也不可能实现。任何想法吗?
5个回答

9

可能有一些黑客方式可以实现,对我来说是有效的。您可以操纵Angular 2组件装饰器,创建自己的装饰器并返回带有您属性的Angular装饰器。

  import { Component } from '@angular/core';

    export interface IComponent {
      selector: string;
      template?: string;
      templateUrl?: string;
      styles?: string[];
      styleUrls?: string[];
      directives?: any;
      providers?: any;
      encapsulation?: number;
    }

    export function CustomComponent( properties: IComponent): Function {
      let aditionalStyles: string;

      try {
          aditionalStyles =  require(`path to aditional styles/${ properties.selector }/style/${        properties.selector }.${ GAME }.scss`);
          properties.styles.push(aditionalStyles);
        } catch (err) {
          console.warn(err)
        }
      }

      return Component( properties );
    }

在您的组件中,将默认的Angular 2 @Component替换为新的组件。

import { CustomComponent } from 'path to CustomComponent';

@CustomComponent({
  selector: 'home',
  templateUrl: './template/home.template.html',
  styleUrls: [ './style/home.style.scss']
})
export class ......

你测试过这个吗? - Chrillewoodz
是的,这对我来说很好用。我正在使用webpack和Angular 2.0.0。 - Virge
@Chrillewoodz,你也试过了吗?我在考虑使用这个实现方式,但可能会为每种样式创建一个新组件,并引用相同的templateUrl和从第三方模块导入所有脚本... - Methodician
是的,但你仍然需要创建一个预先定义的组件样式,它需要被使用,而不是从服务器接收一个样式名称的单个组件,因此并不真正具有动态性。 - Phil
你在那里放了一个额外的括号和未声明的GAME变量! - Alex

7
我已经找到了解决方案:
1. 我将组件装饰器中的styleurls更改为styles。
2. 我会获取我的变量。
3. 我会在我的装饰器中使用require命令。
import { Component } from '@angular/core';
import { environment } from '../environments/environment';
let lang = environment['lang'];

@Component({
   selector: 'app',
   templateUrl: './app.component.html',
   styles: [require('./app.component.css'), require('./app.component.' + lang + '.css')]
  })

  export class AppComponent {

   constructor() { }

  }

在这个基本示例中,我已经导入了环境变量并动态地更改了CSS字符串。

这是我在stackoverflow上的第一个答案。我不明白为什么答案不够好。能否请您解释一下? @Jean-FrançoisCorbett - noah lubko
非常抱歉!那条评论和标记是针对另一个答案的,但不知何故我把它们放到了这里。请忽略!您的回答很好!我不确定当时在哪里看。再次致歉。 - Jean-François Corbett
3
你尝试过在生产环境中使用吗?我认为它在AOT编译器下无法工作。 - Bharat Choudhary
这绝对不能与require一步移除一起使用。我创建了一个带有基础组件类的模块,它还包括export const BASE_COMPONENT_STYLE = require("./base.component.css")。如果我尝试使用styles: [BASE_COMPONENT_STYLE]来创建子类,Ivy会抱怨“无法在编译期间静态评估此表达式”--它无法解析CSS 在编译期间 - Coderer
我在这里做了,但是出现了以下错误:styleUrls必须是字符串数组。有什么建议吗,朋友们? - Andre

1
我曾经有同样的需求,需要动态地注入URL到样式表中,并最终初始化一个组件来处理每个变量CSS(在我的情况下是3种不同的样式),使用空模板将它们用于我的应用程序组件,并通过ngIf条件进行控制。
由于使用了属性“encapsulation: ViewEncapsulation.None”,所选组件的样式会添加到页面头部,并启用整个页面的正确渲染器。

这种方法的问题在于,Angular添加到头部的样式在组件被销毁时不会自动移除。 - FirstVertex
它们从来不会被移除。Angular永远不会删除样式。 - Eliezer Berlin

0

我认为你不能拥有动态样式表URL,因为你无法在@Component装饰器内部访问类属性或方法。

但是你可以通过在模板中拥有动态样式类来实现你的目标。


问题在于我将无法访问模板,只能访问组件本身。 - Chrillewoodz
如果您无法访问模板但仍然想拥有不同的样式,为什么不考虑使用相同模板制作不同组件(采用不同的样式表),并动态加载这些组件呢? - siva636
那可能是一个选项,但它仍然不能提供完全的个性化定制。看起来这是一个功能上的漏洞,他们真的需要解决。 - Chrillewoodz
动态样式类意味着使用 CSS 开销,而不是利用 Sass 变量。对于每个新的皮肤,您都需要重复整个样式表。 - Rohit Rane

-1

我在HTML模板中使用了带有ngIf条件的样式表链接,它对我起作用了。

<link rel='stylesheet' href="/stylesheets/classicTheme.css" *ngIf="theme === 'classic' " />
<link rel='stylesheet' href="/stylesheets/styleTheme.css" *ngIf="theme === 'style' " />

只是好奇这个怎么能够实现?在Angular 2中,“app”运行在_root_元素内(通常位于<body>下方)。那么,你的代码如何绑定到“theme”变量呢? - Eric Liprandi
不要覆盖组件的样式。 - Phil
2
不是说这个方法一定行或者不行,但是虽然大家都认为这个方法因为应用程序运行的位置而行不通,但是这个应用程序可以改变页面标题,对吧?肯定有_某些_访问<head>部分的权限。 - Tim Hobbs

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