1.首先我们要了解Object.defineProperty()方法(明白vue底层动态拦截数据的原理):
vue2的官方文档中:
<script>
new Vue({
el:"#box",
data:{
myname:'',
},
methods:{
}
})
</script>
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter(底层原理)。Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
<body>
<div class="aa"></div>
<script type="text/javascript">
var obj = {
myname:'你好!'
}
// 获取dom元素
var div =document.querySelector('.aa')
div.innerText = obj.myname
// 为obj中的myname属性设置动态拦截
Object.defineProperty(obj,"myname",{
// 当有人访问了这个属性时,会触发这个函数
get(){
// console.log("有人访问了这个数据!")
return div.innerText
},
//当有人重新设置该属性的值时,会触发此函数,并且可以拿到修改后的值:
set(newvalue){
// 给div添加修改后的内容,实现动态的拦截,数据双向绑定。
div.innerText = newvalue
}
})
</script>
</body>
vue底层使用这个方法,实现双向数据绑定,当数据的值被修改后,页面上的数据也会随着一起修改。
2.vue
vue2中
(1)对于数组来说,push,pop,splice,shift,unshift的方法对数组的修改,同样是可以实现动态的拦截的,因为vue重写了这些方法,使他具有了动态拦截的功能。
但这些方法并不具有动态拦截的方法,filter,slice等这些的修改并不会影响原数组,也不会有动态拦截的功能。
(2)对于对象来说,vue2是不支持对于新增属性进行拦截的,也就是说当我们修改这个新增属性的值时,页面并不会随之变化。
解决方法
Vue.set(对象,属性名,true)
let vm=new Vue({
el:'#box',
data:{
obj:{
}
}
})
//data身上的属性都是挂载在vm实例对象上。
//手动拦截
Vue.set(vm.obj,"myname",true)