vue3.0马上要来了,双向数据绑定的方式也由Object.defineProperty()变成了Proxy对象,特地去了解了一下,整理了这2者之间的一些区别
Object.defineProperty()
Object.defineProperty()是通过给对象的某个属性添加getter和setter来监听数据的变化,而我们在setter中对dom进行操作,就达成了简单的双向数据绑定效果了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 为了方便理解使用了vue的语法,可以使用其他的属性 -->
<input type="text" v-model="name" placeholder="请输入名字" />
<div>
你的名字是:
<span v-text="name"></span>
</div>
<input type="text" v-model="age" placeholder="请输入年龄" />
<div>
你的年龄是:
<span v-text="age"></span>
</div>
</body>
let obj = {};
// 监听name属性
Object.defineProperty(obj, "name", {
get: () => {
return name
},
set: (val) => {
name = val
console.log(name);
// 设置给该属性的新值
// 操作dom树,将用到该属性的dom节点进行更新
let list = document.querySelectorAll("[v-text=name]");
for (let i = 0; i < list.length; i++) {
list[i].innerText = name;
}
},
});
// 监听该对应的输入框,在输入值发生变化时,将新值传给对应的属性
document.querySelector("[v-model=name]").oninput = (e) => {
obj.name = e.target.value;
};
Object.defineProperty(obj, "age", {
get: () => {
return age
},
set: (val) => {
age = val
console.log(age)
let list = document.querySelectorAll("[v-text=age]");
for (let i = 0; i < list.length; i++) {
list[i].innerText = age;
}
},
});
document.querySelector("[v-model=age]").oninput = (e) => {
obj.age = e.target.value;
};
效果如下
这样就可以达到双向数据绑定的效果,不过通过Object.defineProperty()设置的必须将每个属性都单独设置,这也就导致在vue中,在后续通过this.xxx添加的数据,并没有双向数据绑定的效果,需要通过set方法添加,才可拥有双向数据绑定的效果
Proxy对象
与Object.defineProperty()不同,Proxy对象无需指定具体要监听的属性,给proxy对象设置了getter和setter方法后,该对象的所有属性都会被监听,但实现双向数据绑定的方法依旧是通过在setter中操作dom树
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p v-text='name'></p>
<input type="text" v-model='name'>
<p v-text='age'></p>
<input type="text" v-model='age'>
<p v-text='gender'></p>
<input type="text" v-model='gender'>
</body>
let obj = {}
let p = new Proxy(obj,{
get(obj,prop){
// getter中给对应的属性添加监听事件
let list = document.querySelectorAll(`[v-model=${prop}]`)
for(let i=0;i<list.length;i++){
list[i].oninput=e=>{
console.log(prop+'input事件')
p[prop]=e.target.value
}
}
return obj[prop]
},
// setter中对dom进行操作
set(obj,prop,val){
console.log(obj)
console.log(prop)
obj[prop]=val
console.log(val)
let list = document.querySelectorAll(`[v-text=${prop}]`)
for(let i=0;i<list.length;i++){
list[i].innerText=val
}
}
})
// 获取页面上所有input标签的v-model绑定的属性,获取proxy对象中对应属性的值来触发getter方法
let input = document.getElementsByTagName('input');
for(let i=0;i<input.length;i++){
console.log(p[input[i].getAttribute('v-model')])
}
效果如下
以上就是基于Object.defineProperty()和Proxy对象的简单的双向数据绑定,可以看到在针对多个属性时,proxy不需要再将对象的属性遍历后添加监听,通过一个公用的监听既可完成双向数据绑定,不得不说也是一大进步,期待vue3.0