有没有一种方法可以将 CSS 类(例如 .angular-app
)添加到 Angular(如 Angular 4)添加到 DOM 的每个单个 HTML 元素?我所说的“每一个 HTML 元素”还指模板中的子元素和孙子元素以及嵌入的内容,即不仅仅是 Angular 组件/指令/主机。
背景:我正在处理一个包含数十万行代码(包括数万行 CSS)的大型单体 AngularJS 项目。现在,该项目的一些 AngularJS 组件应该是 upgraded到 Angular 。不幸的是,AngularJS 项目周围的许多样式都泄漏到 Angular 组件中,并与我们想要在那里使用的样式发生冲突。因此,我们正在考虑的一种解决方案是向 AngularJS 样式的每个选择器添加一个 :not(.angular-app)
选择器(通过 SASS 或一些后处理 Python 脚本),以便它们不匹配 Angular 组件中使用的任何元素。
有什么办法可以解决这个问题吗?
旁注:显然,这个问题可以通过在 Angular 组件的 CSS 中使用 all: revert
或通过创建 ShadowDOM 轻松解决,但由于这些技术几乎不受支持浏览器,我们需要一个中间解决方案。 (为了完整起见,另一种解决方案是向 AngularJS 样式表的每个选择器添加一个 :not()
选择器,以确保我们不在 Angular 组件内,而是在 this would require CSS 4 selectors 内。)
[编辑]:我想这可以通过为 Angular 组件编写自定义渲染器来完成(请参阅 these links ),但我不完全确定如何实现。例如createElement
和 appendElement
由 Angular 本身用于它处理的每个 HTML 元素?
最佳答案
您链接的文章有点过时,实现方式也略有变化。
如果您想实现 Renderer2 的完全任意实现,可以通过使用返回自定义渲染器的 createRenderer
方法简单地实现 RendererFactory2
来实现。
export class MyRenderer implements Renderer2 {
createElement(name: string, namespace?: string) {
const el = document.createElement(name);
el.setAttribute(name, 'marking Angular component');
return el;
}
...
export class MyRendererFactory implements RendererFactory2 {
createRenderer(hostElement): Renderer2 {
return new MyRenderer();
}
...
@NgModule({
providers: [ { provide: RendererFactory2, useClass: MyRendererFactory } ],
...
})
export class AppModule { }
但是,如果您想扩展默认功能,Angular 现在似乎不支持它。 RendererFactory2
的默认实现是 DomRendererFactory2
,它根据封装模式返回 3 种不同的渲染器:
export class DomRendererFactory2 implements RendererFactory2 {
createRenderer(element: any, type: RendererType2|null): Renderer2 {
switch (type.encapsulation) {
case ViewEncapsulation.Emulated: {
return new EmulatedEncapsulationDomRenderer2(this.eventManager, this.sharedStylesHost, type);;
}
case ViewEncapsulation.Native:
return new ShadowDomRenderer(this.eventManager, this.sharedStylesHost, element, type);
default: {
return new DefaultDomRenderer2(eventManager);
}
}
}
不幸的是,这些类都不是
DomRendererFactory2
DefaultDomRenderer2
EmulatedEncapsulationDomRenderer2
ShadowDomRenderer
可作为公共(public) API 使用。
如果您计划单独使用 ViewEncapsulation.Native
,您可以在 DomRendererFactory2
的 defaultRenderer
属性中访问 DefaultDomRenderer2
> 在工厂启动时创建:
@Injectable()
export class DomRendererFactory2 implements RendererFactory2 {
private defaultRenderer: Renderer2;
constructor(private eventManager: EventManager, private sharedStylesHost: DomSharedStylesHost) {
this.defaultRenderer = new DefaultDomRenderer2(eventManager);
}
然后装饰它的createElement
方法:
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent, AComponent, ADirective],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(factory: RendererFactory2) {
const createElement = Object.getPrototypeOf(factory.defaultRenderer).createElement;
Object.getPrototypeOf(factory.defaultRenderer).createElement = function (...args) {
const el = createElement(...args);
el.setAttribute(name, 'marking Angular component');
return el;
}
}
}
但是,该属性是私有(private)的。
您还可以使用提供自定义 Renderer
的第一种方法,并简单地从源代码中复制所有实现。
任何解决方案似乎仍然存在风险。
关于angular - 为 Angular 添加到 DOM 的每个 HTML 元素添加一个 CSS 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46650814/