Vue的响应式
1.基本概念
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty()把这些 property 全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。
2.对于对象
Vue 无法检测对象中键的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以键必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应式的
vm.b = 2
// `vm.b` 是非响应式的对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。
但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于:
Vue.set(vm.someObject, 'b', 2)也可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })3.对于数组
如下所示,通过下标修改数组里的数据,发现并没有卵用
<template>
<div>
<button @click="change">点击</button>
{{ arr[0] }}
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
arr: [1],
}
},
methods: {
change() {
this.arr[0] = 2
},
},
}
</script>
但是当我们打印该值,发现确实已经发生了改变
change() {
this.arr[0] = 2
console.log(this.arr[0])
},
这是因为Object.defineProperty()无法监听到数组值的改变,也无法监听到对象是否新增了键
TIP
vue会监视data中所有层次的数据
对于对象:
通过setter实现监视,且要在new Vue()时就传入要监测的数据
对象创建后追加的属性,Vue默认不做响应式处理
如需给后添加的属性做响应式,请使用如下API
this.set(target,propertyName/index,value)
对于数组:
通过包裹数组更新元素的方法实现,本质就是做了两件事
调用原生对应的方法对数组进行更新
重新解析模板,进而更新页面
在Vue修改数组中的某个元素一定要用如下方法
push()pop()unshift()shift()splice()sort()reverse()这几个方法被Vue重写了Vue.set()或vm.$set()
$set()
$set()是Vue原型上的一个方法,可直接通过this调用
用于修改数组中某个值,或者给对象添加新的键之后,更新视图中的值
$set(target, propertyName/index, value)参数:
- target:data中的对象或者数组,也可以是this
- propertyName/index:数组的下标或者对象的键名
- value:新的值
$forceupdate()
$forceupdate()是Vue原型上的一个方法,可直接通过this调用,用于更新整个视图
不过不推荐使用,因为是更新整个视图
