当前附加DOM事件处理程序的做法是使用Renderer2.listen()
,以防您不需要从模板使用它。这种方法适用于Directive
s \ Component
s。
如果您需要在Service
中执行相同的操作,则问题是尝试将Renderer2
实例注入到服务构造函数中:
export class SomeService {
public constructor(private readonly renderer: Renderer2) {
}
}
将导致缺少DI提供程序异常:
StaticInjectorError(平台:核心)[DefaultValueAccessor-> Renderer2]
为缓解这种情况,我们可以使用RendererFactory2
类进行以下操作:
创建并初始化自定义渲染器,以实现 Renderer2基类。
但是我不确定为在服务中使用新的Render2
是否是一个好的\推荐方法。
所以,问题是在服务中附加DOM事件处理程序的推荐做法是什么?
答案 0 :(得分:2)
其他人评论说,此行为可能更适合Component
或Directive
,但很有趣的一点是可以看到Angular中发生了什么。这是一个非常模块化的框架,这是一个很好的机会来深入了解DI。
Renderer2
在服务方面有点特殊,因为它通过内部Renderer2Interceptor
对 templates 有更多的控制权。与在根级别注入的提供程序或其他全局Angular提供程序相比,它的 scope 也有所不同:由于它用于呈现组件和指令的模板,因此仅适用于那些声明类型。 Angular使用的是一个非常低级的提供程序,用于创建带有视图的声明,因此可以将其注入到视图中-并且由于服务也是@Injectable
,因此Angular DI层次结构分别处理它们,因此Renderer2
在其层次结构中不可用。
使用RendererFactory
是直接 将Renderer2
注入服务的唯一方法。
虽然我认为您对不创建另一个Renderer2
实例的担心是有效的,但请查看有关the Angular repo:的评论
rendererFactory.createRenderer(null, null)
将有所帮助,如果没有 (具体)参数传递,它将只返回默认渲染器 没有创建一个新的。 (原文如此)
因此,使用RendererFactory2.createRenderer(null, null)
只会返回默认的DomRenderer
。工厂可以提供创建 custom 渲染器的能力,而且值得庆幸的是,如果调用了工厂,Angular的维护良好,不会创建重复的DomRenderer
。
因此,只需将RendererFactory2
注入服务并从中获取默认的Renderer2
。
也,谢谢,因为他们知道Renderer
在Angular中很重要,因此努力使用它。直接参与DOM操作的人太多了。