angular - 从服务附加 DOM 事件处理程序
问题描述
附加 DOM 事件处理程序的当前做法是Renderer2.listen()
在您不需要从模板中这样做的情况下使用。这种方法适用于Directive
s \ Component
s。
如果你需要在 a 中做同样的事情Service
,一个问题是试图将一个Renderer2
实例注入到服务构造函数中:
export class SomeService {
public constructor(private readonly renderer: Renderer2) {
}
}
将导致缺少 DI 提供程序异常:
StaticInjectorError(Platform: core)[DefaultValueAccessor -> Renderer2]
为了缓解它,我们可以使用RendererFactory2
类来:
创建并初始化实现 Renderer2 基类的自定义渲染器。
但我不确定是否Render2
为在服务中使用它的情况创建一个新方法是一种好的\推荐方法。
那么,问题是在服务中附加 DOM 事件处理程序的推荐做法是什么?
解决方案
其他人评论说这种行为可能更适合 aComponent
或 a Directive
,但在较低级别看到 Angular 中发生的事情很有趣。这是一个非常模块化的框架,这是一个深入了解 DI 的好机会。
当Renderer2
涉及到服务时,它有点特别,因为它通过 internal对模板Renderer2Interceptor
有更多控制。它还具有与在根级别注入的提供程序或其他全局 Angular 提供程序不同的作用域:因为它用于呈现组件和指令的模板,所以它的作用域仅适用于那些类型的声明。它是一个非常低级的提供者,Angular 使用它来创建带有视图的声明,因此它能够被注入到它们中——并且由于服务也是一个@Injectable
,Angular DI 层次结构单独处理它们,因此Renderer2
不可用在他们的层次结构中。
总而言之,在一个模块中Renderer2
是可用的。declarations
但不是providers
。declarations
是实例并且需要附加模板,但是providers
是单例并且模板对它们没有多大意义。
使用将是直接将 a注入服务RendererFactory
的唯一方法。Renderer2
虽然我认为您对不创建另一个实例的担忧Renderer2
是有效的,但请查看Angular repo 上的此评论:
rendererFactory.createRenderer(null, null)
会有所帮助,如果没有(具体)参数传递,它只会返回默认渲染器而不创建新的渲染器。(原文如此)
因此, usingRendererFactory2.createRenderer(null, null)
只会返回默认值DomRenderer
。工厂的存在是为了提供创建自定义DomRenderer
渲染器的能力,幸好 Angular 维护得很好,如果工厂被调用,就不会创建副本。
因此,只需注入RendererFactory2
服务并从中获取默认值Renderer2
。
另外,感谢您知道Renderer
Angular 中的重要性并努力使用它。有太多人直接进行 DOM 操作。
推荐阅读
- c# - 如何检查一个号码是否包含另一个号码的所有数字?
- r - 水平点图的R plotly高度计算
- sqlite - SQLite:如何将 memvfs 扩展嵌入到合并中?
- python - Python - 从文本文件访问列表中的项目
- vb.net - 这个 RSA 有什么问题,为什么加密/解密的结果不同?
- opengl - EGL 是否需要 GPU?
- bash - 对 package.json 中的 docker 镜像名称进行 Grep
- c# - Polly WaitAndRetry 与最终异常什么都不做
- spring - 如何使用 ThymLeaf 将实体分配给表单中的另一个实体?
- c# - CA1062 未在 .Net Standard 2.0 类库上进行评估