前言
Vue中的数据监听离不开Object.defineProperty()方法的使用,在了解数据监测原理之前,建议先掌握defineProperty的用法。
目标
1 数据监测问题
2 数据监测原理
3 如何实现数组更新
1 遇到的问题
数组更新问题
<button @click="updatePeople">更新一个用户信息</button>
<ul>
<li v-for="(item,index) in people" :key="index">
{{item.name}}----{{item.age}}
</li>
</ul>
// 可以实时更新
updatePeople(){
console.log('更新用户信息')
this.people[0].name = '马冬梅'
this.people[0].age = '40'
},
updatePeople(){
console.log('更新用户信息')
// 实时更新页面失败
this.people[0] = {name:'马冬梅',age:40}
},
vue中的数据更新主要通过Object.defineProperty()中的set来实现的,people数组下的对象没有get与set,而对象中的name、age有set,所以在设置name、age值时会同步的进行更新
Vue.set()
现有一个需求:在页面渲染完成后,动态的给对象添加属性,并打印属性与属性值。
看似很好实现的一个需求,但是当我们的动态的添加属性后,也页面却无任何更新,这是为什么呢?
给data中的属性绑定get、set是在new Vue()的过程中进行绑定的
,但是动态添加属性是在绑定之后,也就是后来添加的属性无set,修改值就无法试试的去监测数据更新了。
为了解决此问题,Vue提供了Vue.set方法,用于添加响应式的property
Vue.set() 与 vm.$set()时一样的效果
Vue.set(vm.pseron,'sex','男生') === vm. $set(vm.pseron,'sex','男生')
Vue.set()也不是任何情况下都可以使用的,若作用的对象是Vue实例或者实例的根数组对象,会无效
data:{
pserson: {
name: "李四",
age: 32,
children: {
name: "王五",
age: 6,
},
}
}
<ul>
<li v-for="(value,key,index) of pserson" :key="index">
{{key}}----------{{value}}
</li>
</ul>
2 Vue检测数据原理
1 对象
在讨论如何解决数组更新问题之前,先来看一下对象是如何实现实时更新的。
详细的就不再描述了,不了解的可以去看看vue 【vue中的数据代理】
对象代理流程大致是:
简单写个例子来模拟一下Vue中对象的数据监听。Vue中对象的数据监听用的也是Object.defineProperty,通过递归遍历对象,确保对象中的每个属性值都有get与set
<script type="text/javascript">
let data = {
name: '张三',
age: '18'
}
const obs = new Observer(data)
let vm = {}
vm._data = data = obs
function Observer(obj) {
const keys = Object.keys(obj)
keys.forEach(key => {
Object.defineProperty(this, key, {
get() {
return obj[key]
},
set(val) {
obj[key] = val
}
})
});
}
</script>
Vue.set()
现有一个需求:在页面渲染完成后,动态的给对象添加属性,并打印属性与属性值。
看似很好实现的一个需求,但是当我们的动态的添加属性后,也页面却无任何更新,这是为什么呢?
给data中的属性绑定get、set是在new Vue()的过程中进行绑定的
,但是动态添加属性是在绑定之后,也就是后来添加的属性无set,修改值就无法试试的去监测数据更新了。
data:{
pserson: {
name: "李四",
age: 32,
children: {
name: "王五",
age: 6,
},
}
}
<ul>
<li v-for="(value,key,index) of pserson" :key="index">
{{key}}----------{{value}}
</li>
</ul>
- 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:- Vue.set(target,propertyName/index, value) 或 vm.$set(target,propertyName/index, value)
2 数组
当数组中对象的属性发生变化时,属性可以实时的监听。但是我们整个改变数组的中的值时,页面却没有实时更新。
我们用数组方法往数组中添加对象,这个对象中的属性也是响应式的
- 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:- (1).调用原生对应的方法对数组进行更新。
- (2).重新解析模板,进而更新页面。
- 在vue修改数组中的某个元素一定要用如下方法:
- 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()。用如下方法向数组中添加对象,对象中的
属性也是响应式
的 - 2.Vue.set()或 vm.$set()
- 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()。用如下方法向数组中添加对象,对象中的
- 特别注意:
Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添属性!!!