响应式数据
概念
如果内存中的数据变化了 页面UI也会动态跟着刷新 这种数据就是响应式数据
响应式数据设计原理:
vue2.0 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter(原型上的属性决定属性的值),在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue3.0 --使用es6 proxy 代理了data对象
响应式数据实现的基础得益于ES6新出的语法Object.defineProperty()创建对象。
Object.defineProperty()的完整写法:
Object.defineProperty(obj,name,{
set(){}
get(){}
})
参数解析:
obj为我们自己创建的对象,在这里就是用这个对象来劫持传入对象数据源中的各个属性;
name为我们设置的属性名;
set(){} 将于自己给属性设置值时触发;
get(){} 将于访问属性时触发,它的返回值就是我们访问属性得到的值。
当然我们也可以用其它方法劫持传入对象的属性,但是其它方法只能劫持不能实现响应式数据,即改变数据时不能实现页面同时刷新。
用代码简单实现这个功能:
<div id="box">
<h1 id="title"></h1>
<p id="msg"></p>
</div>
<script>
//封装函数
function myVue(obj){
let myvue={}
//得到传入对象data的全部属性
let arr=Object.keys(obj.data)
console.log(arr);
for (let i = 0; i < arr.length; i++) {
Object.defineProperty(myvue,arr[i],{
set(v){
obj.data[arr[i]]=v
//响应
let title=document.querySelector(obj.el+" #title")
let msg=document.querySelector(obj.el+" #msg")
title.innerHTML=myvue["title"]
msg.innerHTML=myvue["msg"]
},
get(){
return obj.data[arr[i]]
}
})
//赋值时调用set方法
myvue[arr[i]]=obj.data[arr[i]]
}
return myvue
}
//我们传入的对象,传入myVue后各个属性将会被我们的vue对象劫持
let obj={
el:"#box",
data:{
title:"mytitle",
msg:"mymsg"
}
}
var myvue= new myVue(obj)
</script>
补充一点:
Vue框架劫持对象的属性的值是数组时,数组的下标时不能被劫持的,但是可以劫持数组的方法。所以通过方法修改值。如:
this.arr[2]="hello"//没有劫持数组的下标(不能刷新页面)
this.arr.splice(2,1,"hello")//劫持了数组的方法(可以刷新页面)
此外Vue框架还给我们提供了一个方法:Vue.set(this.arr对象,下标,修改的值)
也可以通过原型上的方法:this.$set(this.arr对象,下标,修改的值)
双向数据绑定
1、如果数据容器中的数据变了也会让页面刷新(dom操作让页面改变);
2、如果用户操作dom,改变了页面,反之也会让数据容器中的数据的值改变。
1是响应式数据原理我们已经实现了,在基础上加上2,我们就形成了双向数据绑定。
1基础上 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
Vue中通过v-model指令实现了双向数据绑定
写一个例子:
<div id="box">
{{msg}}
<input type="text" v-model="msg">
</div>
<script>
new Vue({
el:"#box",
data:{
msg:"mymsg"
}
})
</script>
当我们在标签中修改值时,会动态修改数据源中的数据同步渲染到页面上。