首页 > 解决方案 > 从服务附加 DOM 事件处理程序

问题描述

附加 DOM 事件处理程序的当前做法是Renderer2.listen()在您不需要从模板中这样做的情况下使用。这种方法适用于Directives \ Components。

如果你需要在 a 中做同样的事情Service,一个问题是试图将一个Renderer2实例注入到服务构造函数中:

export class SomeService {
    public constructor(private readonly renderer: Renderer2) {
    }
}

将导致缺少 DI 提供程序异常:

StaticInjectorError(Platform: core)[DefaultValueAccessor -> Renderer2]

为了缓解它,我们可以使用RendererFactory2类来:

创建并初始化实现 Renderer2 基类的自定义渲染器。

但我不确定是否Render2为在服务中使用它的情况创建一个新方法是一种好的\推荐方法。

那么,问题是在服务中附加 DOM 事件处理程序的推荐做法是什么?

标签: angulartypescriptdomdependency-injectionangular-services

解决方案


其他人评论说这种行为可能更适合 aComponent或 a Directive,但在较低级别看到 Angular 中发生的事情很有趣。这是一个非常模块化的框架,这是一个深入了解 DI 的好机会。

Renderer2涉及到服务时,它有点特别,因为它通过 internal对模板Renderer2Interceptor有更多控制。它还具有与在根级别注入的提供程序或其他全局 Angular 提供程序不同的作用域:因为它用于呈现组件和指令的模板,所以它的作用域仅适用于那些类型的声明。它是一个非常低级的提供者,Angular 使用它来创建带有视图的声明,因此它能够被注入到它们中——并且由于服务也是一个@Injectable,Angular DI 层次结构单独处理它们,因此Renderer2不可用在他们的层次结构中。

总而言之,在一个模块中Renderer2是可用的。declarations但不是providersdeclarations是实例并且需要附加模板,但是providers是单例并且模板对它们没有多大意义。

使用将是直接将 a注入服务RendererFactory的唯一方法。Renderer2

虽然我认为您对不创建另一个实例的担忧Renderer2是有效的,但请查看Angular repo 上的此评论:

rendererFactory.createRenderer(null, null)会有所帮助,如果没有(具体)参数传递,它只会返回默认渲染器而不创建新的渲染器。(原文如此)

因此, usingRendererFactory2.createRenderer(null, null)只会返回默认值DomRenderer。工厂的存在是为了提供创建自定义DomRenderer渲染器的能力,幸好 Angular 维护得很好,如果工厂被调用,就不会创建副本。

因此,只需注入RendererFactory2服务并从中获取默认值Renderer2

另外,感谢您知道RendererAngular 中的重要性并努力使用它。有太多人直接进行 DOM 操作。


推荐阅读