Vue 组件传递对象的坑

近期做的一个项目,涉及到一个类似于 dialog 的组件,由于传递的数据比较多,为了偷懒,把部分可选数据统一放到一个对象变量里,打算用对象直接传递,于是,坑就来了。

场景重现

为了方便大家理解,这里我写了一个简单的 demo :

传递的数据很简单,就是一个 info 的对象,里面有 titlecontent 两个属性。

1
2
3
4
5
6
7
8
data() {
return {
info: {
title: "title",
content: ["item1", "item2", "item3", "item4", "item5"]
}
};
}

在组件里,我将 info 对象里的 content 数组删除最后一个,然后显示出来。

1
2
3
created() {
this.info.content.splice(-1, 1);
}

接下来可以点击 demo 里的 Open Dialog 按钮,发现问题了没?对咯,子组件里更新数据,把父组件里的也更新了,按照我这个 demo ,每次点击,父组件里的 content 数组就会少一个,多点击几次后,数组就变空了。

解决方案

其实问题的核心和 Vue 并没有太多关系,这里涉及到的 Javascript 的基础知识,就是值传递和引用传递, Object 和 Array 直接赋值是引用传递,这也就是为什么在子组件里修改,会导致父组件里也更新的原因。

既然明白问题的原因,那解决起来也就很容易了,比如下面这个深拷贝函数,在子组件里处理引用传递的数据前,先进行一次深拷贝。

1
2
3
4
5
6
7
deepcopy(source) {
var result = [];
for (var key in source) {
result[key] = typeof source[key] === 'object' ? deepcopy(source[key]) : source[key];
}
return result;
}

数据进行深拷贝后,似乎就脱离 Vue 的监控了,对数据进行修改, DOM 不会实时更新,我的解决办法的每次修改数据后再进行依次深拷贝,覆盖原数据,不知道各位看官有什么更好的办法?

参考