场景:
页面有新增,编辑,删除按钮,可以编辑表格中的某行数据,页面表格数据是从后台获取的,点击编辑打开dailog,将那行数据赋给ruleForm,发现Form表单无法编辑了,select多选框无法选择,删除,datepicker等组件也会出现这种不能编辑的情况。
select代码如下
<el-select style="margin:0 5px"
v-model="ruleForm.selectValue"
clearable
placeholder="类型">
<el-option v-for="item in group" :key="item.value" :label="item.type" :value="item.value"></el-option>
</el-select>
后台返回数据为row,通过Object.assign进行拷贝
this.ruleForm = Object.assign({},row) //this.ruleForm为表单数据,row为后台返回的数据信息
原因:
通过Object.assign直接将后台返回的数据赋值给form,后台返回的数据中没有select model 绑定的数据,而vue 无法监听动态新增的属性的变化。
data中定义的属性为
ruleForm :{
name:null,
selectValue:null, //select绑定的值
age:null,
address:null
}
而后台返回的数据中没有selectValue属性,如下
temp:{
name:null,
age:null,
address:null
}
解决:
this.ruleForm = Object.assign({},this.ruleForm,row)
<el-select style="margin:0 5px"
v-model="ruleForm.selectValue"
@change="$set(ruleForm,ruleForm.selectValue,$event)"
clearable
placeholder="类型">
<el-option v-for="item in group" :key="item.value" :label="item.type" :value="item.value"></el-option>
</el-select>
浅拷贝和深拷贝
- 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
- 深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
有时候希望在改变新的数组(对象)的时候,不改变原数组(对象)
例如:var newObj = obj; newObj.xxx = xxx
实际上,newObj和obj两个引用指向的是同一个对象,修改了newObj,也就等同于修改了obj。
Object.assign()实现浅复制。
- 合并之后所有被合并的对象和合并的对象都会变
- 如果目标对象中的属性具有相同的键,则它们将被源中的属性覆盖。后来的消息来源的属性将同样覆盖较早的属性。
场景如下:
if(lable === '1'){
this.first= Object.assign([],row);
}else if(lable === '2'){
this.second= Object.assign([],row);
}
console.log(this.first)
console.log(this.second)
这时会发现当label为1时,this.second的值也被改写成与this.first相同的数据
文档中的例子
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // expected output: Object { a: 1, b: 4, c: 5 }
赋值后原本的target也发生了变化,并且b的值变为5
因此在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}
Object.assign() 可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。
- 如果目标对象与源对象有同名属性,则后面的属性会覆盖前面的属性
- 如果只有一个参数,则直接返回该参数。即Object.assign(obj) === obj
- 如果第一个参数不是对象,而是基本数据类型(Null、Undefined除外),则会调用对应的基本包装类型
- 如果第一个参数是Null和Undefined,则会报错;如果Null和Undefined不是位于第一个参数,则会略过该参数的复制
let o1 = { a: 0 , b: { c: 0}};
let o2 = Object.assign({}, o1);
console.log(JSON.stringify(o2)); // { a: 0, b: { c: 0}}
o1.a = 1;
console.log(JSON.stringify(o1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(o2)); // { a: 0, b: { c: 0}}
o2.b.c = 3;
console.log(JSON.stringify(o1)); // { a: 1, b: { c: 3}}//c属性也发生了改变
console.log(JSON.stringify(o2)); // { a: 1, b: { c: 3}}
Object.assign 不会跳过那些值为 null 或 undefined 的源对象。
场景如下:
o1 = {a:1, b:null }
o2 = Object.assign(o1, {a:2,b:3} ); //{a: 2, b: 3}
因此一定要检查后端返回的数据里,有没有属性值为 null或者 undefined,null 和undefined 禁止出现在正常的数据格式中