将外部 CSS 加载到组件中

Posted

技术标签:

【中文标题】将外部 CSS 加载到组件中【英文标题】:Load external CSS into component 【发布时间】:2016-04-05 04:08:57 【问题描述】:
import Component from 'angular2/core';

@Component(
    selector: 'my-app',
    template: '<div></div>',
    styleUrls: [
        'http://example.com/external.css',
        'app/local.css'
    ]
)
export class AppComponent 

external.css 未加载。

有没有办法在 Angular 2 组件中加载外部 CSS?

【问题讨论】:

浏览器控制台是否出现错误? Angular 只是忽略了外部的并且没有加载。 【参考方案1】:

另见https://angular.io/docs/ts/latest/guide/component-styles.html

查看封装

要允许外部样式影响组件的内容,您可以更改视图封装(这就是防止样式“渗入”组件的原因)。

@Component(
    selector: 'some-component',
    template: '<div></div>',
    styleUrls: [
        'http://example.com/external.css',
        'app/local.css'
    ], 
    encapsulation: ViewEncapsulation.None, 
)
export class SomeComponent 

视图封装实现了一个目的。更好的方法是将样式直接添加到它们应该影响的组件中。 ViewEncapsulation 是为每个组件设置的,在某些情况下可能会派上用场。

“阴影穿透”

您还可以使用阴影穿透 CSS 组合器 ::ng-deep&gt;&gt;&gt;/deep/ 已弃用)来构建跨组件边界的选择器,例如

:host ::ng-deep .ng-invalid 
  border-bottom: solid 3px red;

更新 所有新浏览器现在都支持::slotted,并且可以与`ViewEncapsulation.ShadowDomhttps://developer.mozilla.org/en-US/docs/Web/CSS/::slotted一起使用

无论封装是None 还是Emulated,它都会在当前组件中使用类ng-invalid 或任何带有红色下划线的后代设置所有标签的样式。 /deep/ 是否与 Native 一起使用取决于浏览器支持(据我所知,这不再被任何浏览器支持)。

注意

shadow piercing CSS 组合器与 shadow DOM 规范中的组合器相似,但在很长一段时间内它们已被弃用。

使用 默认 ViewEncapsulation.Emulated Angulars 自己的 /deep/::shadow 实现,即使 Chrome 移除原生支持,它们也能正常工作。

ViewEncapsulation.Native Angular 使用 Chrome 的影子 DOM CSS 组合器(无论如何,只有 Chrome 支持它们 AFAIK)。如果 Chrome 最终删除了它们,那么它们也将无法在 Angular 中工作(同样仅限 ViewEncapsulation.Native)。

全局样式

全局添加的样式 (index.html) 不考虑组件边界。 Angular2 不会重写此类样式,ViewEncapsulation.Emulated 不适用于它们。仅当设置了ViewEncapsulation.Native 并且浏览器支持原生 shadow DOM 时,全局样式才不会渗入。

另请参阅此相关问题https://github.com/angular/angular/issues/5390

【讨论】:

P.S.使用封装时,建议将组件选择器写入您的 Local.css 以限制规则目标。 @ZhenyangHua 如何在代码方面做到这一点?你有例子吗? 对不起,应该更清楚。 “这”是指您将encapsulation 设置为无的解决方案。我相信我在我的 Ng2 应用程序中遇到了与 OP 相同的问题,并且在 styleUrls 中声明的外部 css 文件(在我的情况下是从 CDN 提供的)仍未加载并应用于组件。没有错误/警告。同样的调用适用于 Angular1/jQuery,所以它不是 CORS 问题。欢乐时光。 视图封装控制组件样式流血out附加组件的行为,不控制外部样式流血in(它们总是会流血中)。 @GünterZöchbauer,这不起作用plnkr.co/edit/fGvBAimMnjffp4CJnqu2?p=preview【参考方案2】:

首先 - styles/styleUrls 只能用于直接影响模板中元素样式的任何 CSS 规则。

您的 external.css 没有应用于您的组件的原因是,当您从 styleUrlsstyles 在 external.css 中加载这些规则时,在编译时,angular2 将附加一个唯一的组件标识符,如属性选择器到您的原始选择器。

比如在你的external.css中,如果有div.container /*some rules*/ 这样的规则,就会变成div.container[_ngcontent-cds-2] /*some rules*/ 。因此,无论您多么努力地强制您的规则成为优先规则,例如添加!important 标签,它不会起作用——你的external.css 中的所有选择器都被限制为属性选择器的一级,只有组件元素带有相同的属性。这就是 angular2 将样式限制为仅当前组件的方式。

当然总有一种解决方法。

这是我的解决方案——我将添加一个外部资源服务,对于所有 js 脚本,它将使用SystemJS 加载 AMD 或全局,对于所有 css 文件,它将使用纯 javascript 来创建一个&lt;link&gt; 元素并将其附加到&lt;head&gt; 元素。

这是我的一段代码供您参考:

loadCSS(url) 
  // Create link
  let link = document.createElement('link');
  link.href = url;
  link.rel = 'stylesheet';
  link.type = 'text/css';
  
  let head = document.getElementsByTagName('head')[0];
  let links = head.getElementsByTagName('link');
  let style = head.getElementsByTagName('style')[0];
  
  // Check if the same style sheet has been loaded already.
  let isLoaded = false;  
  for (var i = 0; i < links.length; i++) 
    var node = links[i];
    if (node.href.indexOf(link.href) > -1) 
      isLoaded = true;
    
  
  if (isLoaded) return;
  head.insertBefore(link, style);

【讨论】:

您可以将&lt;link&gt; 元素粘贴到component.template html 中,而不是在*script 中执行此操作。但在这种情况下,组件的 css 流出到剩余的应用程序中。 喜欢这个解决方案!【参考方案3】:

这可能会迟到,希望这对其他人有帮助。要使用 ViewEncapsulation,只需使用 import ViewEncapsulation from '@angular/core';

【讨论】:

【参考方案4】:

这里已经发布了更好的方法:https://***.com/a/36265072/5219412

你只需要在你的组件声明中添加这个:

@Component(
    ...
    encapsulation: ViewEncapsulation.None,
)

如角度文档中所述:https://angular.io/guide/component-styles

希望对你有帮助。

【讨论】:

这不是好办法。如上所述,组件不应处理全局样式,即使使用 ViewEncapsulation.None 也不应。如果组件必须影响其自身之外的任何事物,则必须使用该服务。原因是如果现在我们在同一个元素上有多个 CSS 声明,我们会变得一团糟和冲突【参考方案5】:

这里有很多复杂的答案,但我一直发现,如果我想创建一些影响多个组件的样式,它实际上是一种全局样式,因此我将它添加到 styles.css。这个 css 文件很特别,因为它不使用样式封装,所以会影响每个组件。

这在我看来从概念上来说还可以,只是你必须谨慎使用它,否则 style.css 会变得太大。

丰富

【讨论】:

您实际上并没有回答这个问题,只是说“不要这样做,而是这样做”。用户显然想要加载外部 CSS。

以上是关于将外部 CSS 加载到组件中的主要内容,如果未能解决你的问题,请参考以下文章

仅在一个 Vue 组件中包含外部 CSS 库

angular 2组件无法从外部css皮肤加载相对背景图像url

如何将动态外部组件加载到 Angular 应用程序中

从外部重新加载Vue组件

从 Angular 组件动态加载外部 javascript 文件

将外部 HTML 加载到页面中,包括 Javascript 并在加载时启动 JS