Angular单个元素多模板引用变量正常运行的原理是什么?
为什么同一个input上的两个模板引用变量能在不同生命周期钩子正常使用?
嘿,这问题问得好!咱们一点点拆解背后的原理:
1. 两个模板引用变量指向的是不同对象
你在input上声明的两个模板引用,本质上指向完全不同的东西:
#typeAhead="ngbTypeahead":这个引用指向的是NgbTypeahead指令的实例。这里的="ngbTypeahead"是指定引用的是指令导出的名称(指令类上用@Directive({ exportAs: 'ngbTypeahead' })定义的),而非DOM元素本身。#relationTypeInput:这个没有指定导出名称的引用,默认指向input元素的ElementRef实例,也就是直接对应DOM节点的包装对象。
Angular允许在同一个元素上绑定多个模板引用,因为它们的目标对象不冲突——一个是附加在元素上的指令,一个是元素本身。
2. @ViewChild的初始化时机和生命周期钩子的匹配
Angular的@ViewChild查询结果的可用时机,取决于你查询的对象类型:
- 指令/组件实例:这类对象的初始化时机更早。在
ngOnInit钩子触发时,Angular已经完成了组件/指令的实例化和依赖注入,所以你能正常访问typeAhead这个指令实例。不过要注意,如果指令内部依赖DOM元素的渲染状态,可能还是需要延后到ngAfterViewInit,但NgbTypeahead的设计应该允许在ngOnInit访问它的核心方法或属性。 - ElementRef(DOM元素):DOM元素的渲染完成要晚于组件/指令的初始化。Angular会在
ngAfterViewInit钩子触发时,确保所有视图(包括DOM节点)都已经完全渲染并挂载到页面上,所以此时访问relationTypeInput才是最安全的,不会出现“元素未定义”的问题。
你刚好把两个引用的使用时机和它们的初始化时机完美匹配了:在ngOnInit用指令实例,在ngAfterViewInit用DOM元素引用,所以没有报错,运行一切正常。
额外提醒
如果反过来操作——比如在ngOnInit访问relationTypeInput——很大概率会得到undefined,因为此时DOM还没渲染完成;而如果在ngAfterViewInit访问typeAhead当然也没问题,只是没必要延后到这个时机而已。
内容的提问来源于stack exchange,提问作者Bijay Singh
相关产品推荐
相关产品推荐

