angular - 为 Angular 添加到 DOM 的每个 HTML 元素添加一个 CSS 类

标签 angular

有没有一种方法可以将 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 ),但我不完全确定如何实现。例如createElementappendElement 由 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 { }

See demo here .

但是,如果您想扩展默认功能,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,您可以在 DomRendererFactory2defaultRenderer 属性中访问 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;
        }
    }
}

Here is the demo .

但是,该属性是私有(private)的。

您还可以使用提供自定义 Renderer 的第一种方法,并简单地从源代码中复制所有实现。

任何解决方案似乎仍然存在风险。

关于angular - 为 Angular 添加到 DOM 的每个 HTML 元素添加一个 CSS 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46650814/

相关文章:

css - 更改 PrimeNG 中的聚焦输入边框

node.js - 解析器中的 Angular HttpClient 问题

javascript - 如何在不使用按钮的情况下使 Bootstrap 下拉? ( Angular 4+)

angular - [at-loader] node_modules\@types\jasmine 中的错误

html - 使用 Angular2 将 HTML 页面存储在内存中

angular - 获取错误 "No provider for AlertIconAndTypesService!"

angular - Karma 不会 headless 运行 ng 测试

angular - 避免嵌套的可观察对象

Angular Testing 错误 : Can't resolve all parameters for Service:

angular - 如何使用 Angular 创建子模块