Vue2 数据响应式原理
- 数据响应式,是Vue 最独特的特性之一。"响应式",指当数据(model)发生变化时,页面(view)自动更新。
getter 和 setter
- 要理解 Vue2 的数据响应式,要先理解 ES6 的 getter 和 setter、Object.defineProperty
- Vue 通过 Object.defineProperty 将数据进行处理,让 Vue 的实例作为数据的代理并监听数据的变化,并通过 getter 和 setter 来获取数据的变化
- getter 用来读取数据,而 setter 用来更新数据
let myData = {n:0}
let data = proxy({data:myData})
function proxy({data}){
let value = data.n
Object.defineProperty(data, 'n', {
get(){
return value
},
set(newValue){
if(newValue<0)return
value = newValue
}
})
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value) {
data.n = value
}
})
return obj
}
Vue2 数据响应式的局限性和 Vue 的解决方式
- Vue 无法监听对象内部的变化。这是 JS 的局限性造成的
- 如下,点击 setB 并不能使 obj.b 展示在页面中,Vue 无法监听一开始不存在的 obj.b
new Vue({
data: {
obj: {
a: 0
}
},
template:`
<div>
{{obj.b}}
<button @click="setB">setB</button>
<div>
`,
methods: {
setB(){
this.obj.b = 1
}
}
}).$mount('#app')
- 解决方法:
- 将所有属性提前声明好,初始化值为 null 或者 undefined
- 使用 Vue.set() / this.$set()
- this.$set() 会自动新增一个 key,并自动创建代理和监听(如果没有创建过)
new Vue({
data: {
obj: {
a: 0
}
},
template:`
<div>
{{obj.b}}
<button @click="setB">setB</button>
<div>
`,
methods: {
setB(){
this.$set(obj.b, 'b', 1)
}
}
}).$mount('#app')
- 数组的变异方法
- 对数组来说,我们只能使用使用 Vue.set() / this.$set(),因为没有办法提前预知有多少个元素
- Vue 改造了数组的 api,在原型链中加入了 7 个变异方法,这些变异方法会自动调用 this.$set,并调用原来的数组方法
- 这些变异方法包括:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
new Vue({
data: {
array: ['a', 'b', 'c']
},
template:`
<div>
{{array}}
<button @click="setD">setD</button>
</div>
`,
methods: {
setD(){
this.array.push("d")
}
}
}).$mount('#app')