Angular父子Mat Dialog传参致对象属性被意外修改问题排查
Mat Dialog传递对象后修改子组件数据导致父组件原数据污染的问题分析
错误原因
你用{...this.scenarios[i]}或Object.assign({}, this.scenarios[i])做的是浅拷贝:
- 浅拷贝只会复制对象的第一层基本类型属性(比如
id、name这些字符串/数字),但对于ScenarioPreview里的photos数组这种引用类型,浅拷贝只会复制数组的内存引用,不会创建新的数组实例。 - 这就导致子组件中
this.scenario.photos和父组件this.scenarios[i].photos指向的是同一个数组,你在子组件中修改数组元素时,本质上是直接修改了父组件的原数据。每次打开预览都会重复添加前缀,自然就出现了叠加的问题。
解决方法
需要对包含引用类型的对象做深拷贝,确保子组件操作的是完全独立的数据副本,以下是几种可行的实现方式:
方式1:在父组件传递数据时手动深拷贝
openPreviewModel(i: number) { const originalScenario = this.scenarios[i]; // 复制所有属性,并重新创建photos数组,切断引用 const copiedScenario = { ...originalScenario, photos: [...originalScenario.photos] }; this.matDialog.open(PreviewScenariosComponent, {data: copiedScenario}); }
如果要结合你的ScenarioPreview类,可以这样写:
openPreviewModel(i: number) { const original = this.scenarios[i]; const copied = new ScenarioPreview({ ...original, photos: [...original.photos] }); this.matDialog.open(PreviewScenariosComponent, {data: copied}); }
方式2:在子组件中创建独立副本后再修改
ngOnInit(): void { // 先创建包含独立photos数组的副本,再进行修改 this.scenario = { ...this.data, photos: [...this.data.photos] } as ScenarioPreview; for (let j = 0; j < this.scenario.photos.length; j++) { let base64_photo = this.scenario.photos[j]; this.scenario.photos[j] = `data:image/png;base64,${base64_photo}`; } this.current_photo = this.scenario.photos[this.current_photo_index]; }
方式3:使用结构化克隆API(简洁版)
如果你的环境支持structuredClone(现代浏览器及Node.js 17+),可以直接用它做深拷贝:
openPreviewModel(i: number) { const copiedScenario = structuredClone(this.scenarios[i]); this.matDialog.open(PreviewScenariosComponent, {data: copiedScenario}); }
内容的提问来源于stack exchange,提问作者Brave Spirit
相关产品推荐
相关产品推荐

