1.数据响应式是什么?
数据响应式是指视图页面根据数据的变化做出相应的变化。
举一个简单的例子:
对于模板:
<div id="app">{{ name }}</div>
创建一个Vue实例:
var vm = new Vue({
el:'#app',
data:{
name:'Pray'
}
})
执行以上代码后,页面显示 Pray。
vm.name = 'Frank'
执行代码以上后,页面更新为 Frank,并不需要去手动修改 DOM 更新数据。
2.原理浅析
我们先来理一下逻辑,Vue的数据响应式的逻辑其实很简单:
数据变动 -> Vue捕获到数据变动 -> 重新渲染
所以问题的关键就在于Vue是怎么样捕获到数据的变动的呢?
答案是通过设置访问器属性getter与setter。
关于getter/setter的作用可以看看这篇文章getter/setter的作用.
简单点来说就是:
-
getter是读取对象属性时调用的函数。 -
setter是写入对象属性时调用的函数。
所以Vue捕获数据变动就以通过setter函数——当数据变化(被写入值)时,JS会调用的set()函数,我们只需要在set()函数中写入渲染函数render()实现即可:
Object.defineProperty(vm,"name",{
get(){
return this.name;
},
set(newValue){ //vm.name = 'Frank' 时执行 set 函数
vm.name = newValue;
render(); //重新渲染
}
})
注:以上实现仅为简略的介绍Vue数据响应式的原理,实际实现远比其复杂
3.数据响应式的注意事项
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化
对于对象
Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 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)
this.$set(this.someObject,'b',2) //this.$set 是 Vue.set 另一种写法
对于数组
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 // 不是响应性的
解决方法:
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:
Vue.set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,你可以使用 splice:
vm.items.splice(newLength)
如果是添加或删除数组头或尾,Vue提供的push,pop,shift,unshift方法都是可以给新数据添加响应式的。