吹牛之前先摆哈NBA,大威少这赛季的投篮是真的铁,下图比喻得栩栩如生...... 然后今天北京时间2022/5/13 热火4-276人(数字人),三弟(登哥)持续低迷14中2将数字人全队带去钓鱼了,正式出局季后赛......
好了,进入正题,
vue2的双向数据绑定是利用ES5的一个API Object.definePropert() 对数据进行劫持,结合发布订阅模式的方式来实现的。
vue3中使用了ES6的Proxy这个API来对数据代理。
两者区别:Object.definePropert() 只能监听某个属性,不能对全对象监听。 而Proxy 可以省去for in、Object.keys()等操作来提升效率(直接绑定整个对象即可), 也可以监听数组,不用再去单独的对数组做特异性操作,它可以检测到数组内部数据的变化。
vue2/vue3原理实现:
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<input type="text" id="inputVue2" /> vue2输入的值为:<span id="outVue2"></span><br />
<input type="text" id="inputVue3" /> vue3输入的值为:<span id="outVue3"></span>
</body>
</html>
<script type="text/javascript">
//vue2双向绑定实现原理
const data = {// 定义一个对象
age: 10
};
var val = data.age;
var inputVue2 = document.querySelector('#inputVue2');
var outVue2 = document.querySelector('#outVue2');
// 遍历对象 实现对对象的属性进行劫持
Object.keys(data).forEach(key => {//这里也可以用for in
Object.defineProperty(data, key, {
// 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中
enumerable: true,
// 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除
configurable: true,
// 一个给属性提供 getter 的方法
get: () => {
return val;
},
// 一个给属性提供 setter 的方法
set: (newVal) => {
// 当属性值发生变化时我们可以进行额外操作 如调用监听器
if (newVal === val) { // 如果未发生变化 不做其他操作
return;
}
outVue2.innerHTML = newVal
console.log(`vue2触发视图更新函数${newVal}`);
},
})
})
inputVue2.addEventListener('input', e => data.age = e.target.value)
//vue3双向绑定实现原理
let obj = { // 源数据对象
sex: '女',
height: 168
}
var inputVue3 = document.querySelector('#inputVue3');
var outVue3 = document.querySelector('#outVue3');
let proxy = new Proxy(obj, {
get: (target, prop, receiver) => {
return prop in target ? target[prop] : 0
},
// input事件触发进行劫持,触发update方法
set: (target, prop, value, receiver) => {
target[prop] = value
console.log(`vue3触发视图更新函数${value}`);
update(value)
}
})
// update方法用于同步dom更新
const update = (value) => {
outVue3.innerHTML = value
inputVue3.value = value
}
// 监听input数据变化,并修改proxy的值
inputVue3.addEventListener('input', e => proxy.text = e.target.value)
</script>