将外部 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】:首先 - styles
/styleUrls
只能用于直接影响模板中元素样式的任何 CSS 规则。
external.css 未应用于组件的原因是,当您从 styleUrls
或 styles
在 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 来创建一个<link>
元素并将其附加到<head>
元素。
这是我的一段代码供您参考:
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);
【讨论】:
您可以将<link>
元素粘贴到component.template html
中,而不是在*script 中执行此操作。但在这种情况下,组件的 css 流出到剩余的应用程序中。
喜欢这个解决方案!【参考方案2】:
另见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
(>>>
和 /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【参考方案3】:
这里已经发布了更好的方法:https://***.com/a/36265072/5219412
你只需要在你的组件声明中添加这个:
@Component(
...
encapsulation: ViewEncapsulation.None,
)
如角度文档中所述:https://angular.io/guide/component-styles
希望对你有帮助。
【讨论】:
这不是好办法。如上所述,组件不应处理全局样式,即使使用 ViewEncapsulation.None 也不应。如果组件必须影响其自身之外的任何事物,则必须使用该服务。原因是如果现在我们在同一个元素上有多个 CSS 声明,我们会变得一团糟和冲突【参考方案4】:这可能会迟到,希望这对其他人有帮助。要使用 ViewEncapsulation,只需使用
import ViewEncapsulation from '@angular/core';
【讨论】:
【参考方案5】:这里有很多复杂的答案,但我一直发现,如果我想创建一些影响多个组件的样式,它实际上是一种全局样式,因此我将它添加到 styles.css。这个 css 文件很特别,因为它不使用样式封装,所以会影响每个组件。
这在我看来从概念上来说没问题,只是你必须谨慎使用它,否则 style.css 会变得太大。
丰富
【讨论】:
您实际上并没有回答这个问题,只是说“不要这样做,而是这样做”。用户显然想要加载外部 CSS。以上是关于将外部 CSS 加载到组件中的主要内容,如果未能解决你的问题,请参考以下文章
angular 2组件无法从外部css皮肤加载相对背景图像url