就像响应式页面一样,Vue的数据响应式就是在数据发生改变时能够在页面上反应出来。例如
const vm = new Vue ({data:{n:0}),如果修改了vm.n,那么UI中的n就会响应。
1. 追踪数据变化
1.1 关于getter 和 setter
- getter——用于获取值。在函数前面加上 get 即可获取到函数值,之后使用函数值时不需要加函数括号()。(可理解为不加括号的函数)(读属性)
- setter——修改原值。有 get 就有 set ,setter需要传入参数。(写属性)
例 1: get
let obj2 = {
get 姓名() { //get——获取一个值
return this.姓 + this.名;
}
};
console.log("需求二:" + obj2.姓名);//这里不需要函数的括号()
例 2: set
let obj3 = {
姓: "高",
名: "圆圆",
set 姓名(xxx){
this.姓 = xxx[0] //不考虑复姓得到姓
this.名 = xxx.slice(1)
}
};
obj3.姓名 = '刘诗诗'
console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`)
1.2 Object.defineProperty()
Object.defineProperty()——会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
在Vue里,定义完一个对象之后,想在这个对象添加新的属性,就使用Object.defineProperty()。
Object.defineProperty()内传入的参数:第一个是要操作的对象;第二个是要定义的属性的名字(例如xxx);第三个参数,如果含有get或set,就不需在其后面加属性名。但是由于xxx属性不存在,所以需要找一处放置xxx属性的值(例如x)。且get返回时不能返回属性xxx,因为xxx不存在会不停的调用get结果陷入死循环。
var x = 10 //放置 xxx 的值
Object.defineProperty(obj3,'xxx',{
get(){
return x //不能返回xxx,xxx属性不存在
},
set(value){
x = value // 这里也是不能写成 xxx = value
}
})
2. 新增key(对于对象)
Vue.set 或者 this.$set
由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:
var vm = new Vue({
data:{
a:1
}
})
// vm.a是可以显示的
// 但是 vm.b不会显示,因为 vm.b 不存在
对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。
解决方法:
- 一开始将对象的key就声明好;
- Vue.set 或者 this.set(this.obj,'b',1) === Vue.set(this.obj,'b',1))
new Vue({
data: {
obj: {
a: 0 // obj.a 是响应式的
}
},
template: `
<div>
{{obj.b}}
<button @click="setB">set b</button>
</div>
`,
methods: {
setB() { //新添 obj.b 响应式
this.$set(this.obj,'b',1)
//或 Vue.set(this.obj,'b',2)
}
}
}).$mount("#app");
Vue.set 和 this.$set的作用:
- 新增key;
- 自动创建代理和监听;
- 触发UI更新。
3. 新增key(对于数组)
3.1 对于数组
Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue - 当你修改数组的长度时,例如:
vm.items.length = newLength例如:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
当data内是数组时,也可以通过Vue.set或者this.$set添加修改key,但是也可以用被包裹的数组变更方法。(具体可看3.2 变更方法)
3.2 变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。(Vue将数组的API进行了更改,当数组在Vue内时,会在数组的原型中加上一层原型链。)这些被包裹过的方法包括:
push()pop()shift()unshift()splice()sort()reverse()这 7 个API会自动处理监听和代理,同时也将在响应式系统内触发状态更新。以.push()为例:
new Vue({
data: {
array: ["a", "b", "c"]
},
template: `
<div>
{{array}}
<button @click="setD">set d</button>
</div>
`,
methods: {
setD() {
this.array.push('d') // 更新显示[ "a", "b", "c", "d" ]
}
}
}).$mount("#app");
参考:Vue的深入响应式原理