对象
简单模拟
const data = {
name: "Jack",
age: 19,
};
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data);
//准备vm实例对象
const vm = {};
vm._data = data = obs;
const Observer = function (obj) {
//汇总对象中所有的属性
const keys = Object.keys(obj);
//遍历
keys.forEach((k) => {
//this指向当前实例对象obs
Object.defineProperty(this, k, {
get() {
return obj[k];
},
set(val) {
//修改了数据,进行解析-生成虚拟DOM等操作,来更新页面...
obj[k] = val;
},
});
});
};
Vue.set()
在我们使用 vue 进行开发的过程中,可能会遇到一种情况:当生成 vue 实例后,当再次给数据赋值时,有时候并不会自动更新到视图上去; 当我们去看 vue 文档的时候,会发现有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。 如下代码,给 student 对象新增 age 属性
data () {
return {
student: {
name: '',
sex: ''
}
}
}
mounted () { // ——钩子函数,实例挂载之后
this.student.age = 24
}
一句话来说,就是在创建 vm 示例之后添加的属性,都不是响应性的,视图无法监听并更新。所以借用一个 API 来解决此类问题,即添加属性并且具备响应性Vue.set(target,key,val)
所以代码应该写为:Vue.set(vm.student,'age',22)
或者使用实例对象上的$set:vm.$set(vm.student,'age',22)
在 vm 对象内使用,this 指向 vm。但是,Vue.set 的 target 不允许是 vm 对象本身或者 vm._data
数组
数据类型为数组时,没有为 index 服务的 getter 和 setter,所以更改数组时候无法使用数组 + 索引值的方法来动态更新(可以修改)。但是可以通过 pop,push,unshift,shift,splice,sort,reverse 这些能修改原数组的方法来响应式地更新值。原因:包装,这些方法不是原生的 Array.prototype.push,而是 vue 自身包装的 push 方法。可以用 Vue.set 和 vm.$set 实现:Vue.set(this.arr,index,value)
或者使用 splice 方法:this.arr.splice(index0,index1,'value')
总结
1.vue 会监视 data 中所有层次的数据
2.如何监测对象中的数据?
通过 setter 实现监视,且要在 new Vue 时就传入要监测的数据。对于后追加的属性默认不做响应式处理,请使用 Vue.set()或 vm.$set()
3.如何监测数据中的数据
通过包裹数组更新元素的方法实现,本质就是先调用原生对应方法对数组进行更新,然后重新解析模板进而更新页面
4.Vue 修改数组中的某个元素
使用修改数组的 7 个 API 或者 Vue.set() / vm.$set()
注意:Vue.set()和 vm.$set()不能给 vm 或 vm 根数据对象(vm._data)添加属性