一、什么是数据响应式?
- 对外界的变化做出反应即为响应式。
const vm = new Vue({data:{n: 0}}),当修改 vm.n 或 data.n 时,render(data…) 中的 n 就会做出相应的响应,这就是 vue 的 数据响应式。- vm相当于data的代理
二、如何实现数据响应式?
1.通过getter和setter修改对象属性实现数据响应
getter 是获取某个特定属性的值的方法; setter 是设定某个属性的值的方法
用代码说明一下:
let obj1 = {
姓: "高",
名: "圆圆",
age: 18
}
声明一个对象,如果我想得到该对象的姓名,可以在该对象里再添加一个名为“姓名”的函数,调用它即可:
let obj1 = {
姓: "高",
名: "圆圆",
姓名(){
return this.姓 + this.名
},
age: 18
}
console.log(obj1.姓名()) //打印出 高圆圆
使用 getter 也可以达到相同的效果:
let obj1 = {
姓: "高",
名: "圆圆",
get 姓名(){
return this.姓 + this.名
},
age: 18
}
console.log(obj1.姓名) //打印出 高圆圆
getter 的用法就是这样,通俗来说,就是一个调用时不需要加括号的函数
同理,setter 的用法也大致相同:
let obj1 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
set 姓名(xxx){
this.姓 = xxx[0]
this.名 = xxx.slice(1)
},
age: 18
}
obj1.姓名 = '刘诗诗'
console.log(`姓 ${obj1.姓},名 ${obj1.名}`) //打印出 姓 刘,名 诗诗
用 = xxx 触发 set 函数
注意: “姓名” 并不是一个真实的属性,因为 obj1 在定义时并没有写“姓名”这个属性,这个意思是说我们可以通过 get 和 set 对“姓名”属性进行读和写,但是并不存在一个叫“姓名” 的属性。
2.Object.defineProperty
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
例如在对象 obj1 中增加 getter、setter
let _xxx = 0;//可声明一个局部变量或者全局变量来使用,不可直接用 xxx
Object.defineProperty(obj1, "xxx", {
get() {
return _xxx;//新定义的xxx是不存在的,不能在get|set里return xxx,会死循环
},
set(newValue) {
_xxx = newValue;
}
});
Object.defineProperty存在一些问题
- Vue只会检查第⼀层属性
- 必须要有‘n’,才能代理和监听obj.n,没有会出现警告
解决方法
使用Vue.set或this.$set
Vue.set和this.$set作用
- 新增key
- 自动创建代理和监听(如果没有创建过)
- 触发更新UI(但不会立刻更新)
3.使用代理
vm=new Vue({data:myData}),让vm成为myData的代理(proxy),会对myData的所有属性进行监控
监控目的:防止myData的属性变了,vm不知道
vm知道属性改变才可以调用render(data),UI=render(data)
三、数组变异
data中有数组怎么办?
vue对数组进行了改变,给数组加了一层原型,在其中Vue修改了7个方法覆盖了之前数组原型的7个方法。调用这些Vue新定义的方法时,在这些新方法里Vue会加上对新添的元素的监听(相当于进行了set操作),把新数据也进行代理,这样vue就能重新监测到数组的变化了更新UI操作
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
四、总结
对象中新增的key
- Vue没有办法事先监听和代理
- 要使用set来新增key,创建和监听代理,更新UI
- 最好提前把属性都写出来,不要新增key
- 但数组做不到“新增key”
数组中新增key
- 也可用set来新增key,更新UI
- 不过尤雨溪修改了7个API方便对数组进行增删
- 这7个API会自动处理监听和代理,并更新UI
结论:数组新增key最好通过7个API