Angular模板引用变量绑定按钮点击及聚焦功能报错问题
问题根因
- 元素查询装饰器使用错误:
@ContentChild仅能查询组件标签包裹的、从父组件传入的投影内容,你的第一个按钮是直接写在当前组件自身模板中的元素,不属于投影内容,因此@ContentChild永远无法获取到该按钮实例,elOnNo值为undefined,调用其下属性自然会抛出空引用错误。 - 模板引用变量名不匹配:你给第一个按钮定义的模板引用变量是
#b,但装饰器中传入的查询标识为'onNo',二者名称完全不对应,即便使用正确的装饰器也无法匹配到目标元素。 - 焦点触发时机冲突:
focusout事件触发时,浏览器默认的Tab键焦点切换逻辑尚未执行完成,此时同步调用focus()方法会被原生焦点行为覆盖,无法达到预期效果,甚至可能触发焦点事件循环。
修复步骤
- 修正元素查询逻辑:同组件模板内的元素需要使用
@ViewChild装饰器查询,同时统一模板引用变量名。
调整第一个按钮的模板代码,将模板引用变量名改为可识别的命名:
对应修改TS类中的元素查询代码:<button (click)="accessButton(btnNo)" #btnNo>Click me!</button>// 查询名与模板#后定义的变量名完全一致,使用@ViewChild查询模板内元素 @ViewChild('btnNo', { static: false }) elOnNo: ElementRef; - 调整焦点调用时机:将焦点设置逻辑包裹在零延迟
setTimeout中,等浏览器原生焦点切换流程执行完成后再触发自定义焦点跳转,同时增加空值判断兜底:onFocusOut($event: FocusEvent) { setTimeout(() => { // 可选安全判断,避免元素未渲染时报错 this.elOnNo?.nativeElement?.focus(); }, 0); } - 可选体验优化:增加焦点目标判断,仅当用户按Tab键将焦点切出当前按钮组/页面时才触发焦点回退,避免鼠标点击其他区域失焦时被强行拉回焦点:
onFocusOut($event: FocusEvent) { // relatedTarget为失焦后即将获得焦点的元素,不存在时代表焦点切出当前文档 if (!$event.relatedTarget) { setTimeout(() => { this.elOnNo?.nativeElement?.focus(); }, 0); } }
内容的提问来源于stack exchange,提问作者Nag Arjun
相关产品推荐
相关产品推荐

