Angular中二维数组渲染输入框按键后焦点异常跳转问题求助
Angular二维数字数组双向绑定焦点异常跳转的原因
场景复现
在Angular项目中定义了如下二维数字数组:
[ [1,1,1,1], [1,1,1,1] ]
通过*ngFor指令循环生成输入控件:
<table> <tbody> <tr *ngFor="let d of myData"> <td *ngFor="let factor of d; let i = index"> <input type="number" [(ngModel)]="d[i]"> </td> </tr> </tbody> </table>
异常现象
- 每次按下按键后,焦点会跳转到同行的下一个输入框;到行尾后焦点移出,无法跳转到下一行
- 输入值时,同行后续输入框会显示前一个输入框的值,但数组对应元素的实际值并未改变
- 将内部数组元素从
number类型改为{ value: 1 }这类对象类型后,异常跳转现象完全消失
原因分析
核心问题出在Angular的*ngFor跟踪机制和变更检测逻辑上:
*ngFor默认采用值跟踪,对于number这类原始数据类型,当你通过双向绑定修改数组元素值时,原数值会被替换为新数值——Angular会认为这个元素是一个全新的对象,因此会销毁原来的输入框DOM节点,重新创建一个新的输入框。- DOM节点的销毁重建会打乱浏览器的焦点管理,导致焦点自动跳转到下一个输入框;同时由于DOM重建和数组更新的时序差,会出现后续输入框显示值异常的情况。
- 当使用对象类型时,我们修改的是对象内部的
value属性,对象本身的引用并未改变——*ngFor会识别到这是同一个元素,不会触发DOM的销毁重建,因此焦点和双向绑定都能正常工作。
替代解决方案(无需修改数据结构)
如果不想将原始类型改为对象,可以给*ngFor添加trackBy函数,基于索引跟踪元素,避免DOM不必要的重建:
- 在组件类中定义跟踪函数:
trackByIndex(index: number): number { return index; }
- 修改模板中的
*ngFor指令:
<td *ngFor="let factor of d; let i = index; trackBy: trackByIndex"> <input type="number" [(ngModel)]="d[i]"> </td>
内容的提问来源于stack exchange,提问作者Miro J.
相关产品推荐
相关产品推荐

