目录
一、结论
- vue2.0,通过ES5中的
defineProperty
实现数据双向绑定 - vue3.0,通过ES6中的
Proxy
实现数据双向绑定
二、vue2.0原理
2-1、实现步骤
第一步:声明一个对象,并克隆该对象
let obj={
name:""
};
let newObj=JSON.parse(JSON.stringify(obj))
第二步:通过 Object.defineProperty
劫持 set
和 get
Object.defineProperty(obj,"name",{
get(){
return newObj.name;
},
set(val){
newObj.name=val;
observer();//调用第三步中封装的方法,数据变化时修改视图内容
}
})
第三步:封装一个方法,数据变化时修改视图内容。同时监听页面变化,并修改数据。
function observer(){ //(奥博惹窝)观察者
divName.innerHTML= obj.name;
inpName.value = obj.name;
}
inpName.oninput=function(){
obj.name=this.value;//this指向input输入框
}
2-2、完整代码示例
<body>
姓名: <div id="divName"></div>
<br>
<input id="inpName" type="text">
<script>
let obj={
name:""
};
let newObj=JSON.parse(JSON.stringify(obj));//克隆对象
// defineProperty,给对象定义属性
Object.defineProperty(obj,"name",{
// 获取obj.name时会触发get
get(){
return newObj.name;//必须有一个返回值,否则通过obj.name获取到的值就是underfind
// return obj.name;//错误用法。如果使用obj.name,会陷入死循环,因为obj.name就是获取值,会触发get
},
// 给obj.name赋值时会触发set
set(val){
if(val===newObj.name) return;
newObj.name=val;//当obj.name值修改时,同步修改newObj
observer()
}
})
// 修改数据
setTimeout(()=>{
obj.name="张三"
},1000)
// 数据的更改,影响视图的变化。相当于vue中的双大括号插值法{{}}
function observer(){ //奥博惹窝,观察者
divName.innerHTML= obj.name;
inpName.value= obj.name;
}
// 视图的变化,影响数据的更改。相当于vue中的v-model
inpName.oninput=function(){
obj.name=this.value;//this指向input输入框
}
</script>
</body>
2-3、vue2.0通过defineProperty实现数据双向绑定的问题
-
- 需要对原始数据克隆。
-
- 需要分别给对象中的每一个属性设置监听。
- Vue文档有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
- 所以在vue中有一个问题是,data中的对象,如果刚开始没有定义某个属性,后来通过 “对象.属性” 这种方法给对象添加了这个属性,那么vue是没有对这个属性进行监听的。
- 解决方法是通过
$set
方法给对象添加属性,this.$set(this.obj,'sex', '男')
或Vue.set(this.obj,'sex', '男')
- 需要分别给对象中的每一个属性设置监听。
二、vue3.0原理
3-1、原理: 通过Proxy
劫持get
和set
。
let obj={};
obj = new Proxy(obj,{ //Proxy(泼可谁)
get(target,prop){
return target[prop];
},
set(target,prop,value){
target[prop]=value;
observer();//修改数据时,修改视图内容
}
})
其他步骤和vue2.0类似。
3-2、完整代码示例
<body>
姓名: <div id="divName"></div>
<br>
<input id="inpName" type="text">
<script>
let obj={};
obj = new Proxy(obj,{
get(target,prop){
return target[prop];
},
set(target,prop,value){
target[prop]=value;
observer();//修改数据时,修改视图内容
}
})
// 修改数据
setTimeout(()=>{
obj.name="张三"
},1000)
// 数据的更改,影响视图的变化。相当于vue中的双大括号插值法{{}}
function observer(){
divName.innerHTML= obj.name;
inpName.value= obj.name;
}
// 视图的变化,影响数据的更改。相当于vue中的v-model
inpName.oninput=function(){
obj.name=this.value;//this指向input输入框
}
</script>
</body>