Vue3的双向数据绑定原理主要依赖于两个核心概念:响应式系统和虚拟DOM
Vue3.0中的响应式采用了ES6中的Proxy方法。
特点:
- Proxy 作为新标准将受到浏览器厂商重点持续的性能优化
- Proxy 能观察的类型比 defineProperty 更丰富,而且 Proxy 支持监听数组与嵌套属性的变化,使得 Vue3 的响应式能力更强。
- Proxy 不兼容IE,也没有 polyfill, defineProperty 能支持到IE9
- Vue2中Object.definedProperty 是劫持对象的属性,新增元素需要再次 definedProperty。而 Proxy 劫持的是整个对象,不需要做特殊处理
- 使用 defineProperty 时,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截
Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)
语法:
const p = new Proxy(target, handler)
参数target
表示要使用Proxy
包装的对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
参数handler
是一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理p
的行为
let obj = {
a: 1,
b: 2
}
const proxy = new Proxy(obj, {
get: function(target, prop, receiver) {
return prop in target ? target[prop] : 0
},
set: function(target, prop, value, receiver) {
//目标对象,属性名,属性值,Proxy对象本身,最后一个参数可选。
target[prop] = 666
}
})
console.log(proxy.a) // 1
console.log(proxy.c) // 0
proxy.a = 10
console.log(proxy.a) // 666
obj.b = 10
console.log(proxy.b) // 不是666 而是10
以上代码中obj是我们要代理的目标对象,get,set方法是参数handler的两个属性,具体如下:
handler.get()接收三个参数,第一个参数target为代理的目标对象,第二个参数prop是代理的目标对象的属性,第三个参数是Proxy或者继承Proxy的对象,通常是proxy本身。
handler.set()接收四个参数,其中三个参数都与get方法相同,唯独多出来一个value表示新的属性值。
上述代码表示当访问proxy的属性时,进行拦截判断,该属性是否是目标对象的属性,如果是那么就将其值返回出来,否则就返回0。
当对proxy上的属性进行重写时,将重写的该属性赋值为666。
注意: 此时对数据的劫持,只是劫持了代理对象proxy
,而跟原对象obj
没有任何关系,对obj
进行操作,也不会监听到。
用proxy
实现一个简易版的数据响应:
<body>
<h2 id="app"></h2>
<input id="input" type="text" />
</body>
let app = document.getElementById('app')
let input = document.getElementById('input')
let obj = { // 源数据
text:'hello world'
}
let proxy = new Proxy(obj, {
set: function(target, prop, value){ // input事件触发进行劫持,触发update方法
target[prop] = value
update(value)
}
})
function update(value){ // update方法用于同步dom更新
app.innerHTML = value
input.value = value
}
input.addEventListener('input',function(e){ // 监听input数据变化,并修改proxy的值
proxy.text = e.target.value
})
proxy.text = obj.text // 初始化源数据