vue3实现数据双向绑定的数据挟持
vue3数据挟持原理
主要利用Proxy进行代理
Proxy介绍
const proxyData = new Proxy(target, proxyConf)
是 JavaScript 中创建代理对象的核心语法,用于拦截并自定义对目标对象target
的操作
const proxy = new Proxy(target,proxyConf)
核心参数
target
目标对象可以是任何类型的对象(包括数组、函数、其他 Proxy 对象等)
代理对象
proxyData
会继承target
的原始行为,但通过proxyConf
可以覆盖或增强这些行为。proxyConf
处理程序对象包含一系列 陷阱方法(Traps),用于拦截对 target 的操作
若未定义某个陷阱方法,则默认执行原始操作(如直接访问
target
的属性)
代码实现
<!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>
<button class="but">改变</button>
<div class="content"></div>
<script>
// 利用Proxy
const updateView = () => {
console.log('视图跟新')
}
const reactive = (obj = {}) => {
if (typeof obj !== "object" || obj == null) {
return obj
}
// Proxy 处理程序对象
const proxyConf = {
get(target, key, receiver) {
const keys = Reflect.ownKeys(target) // 获取属性
if (keys.includes(key)) {
console.log('获取数据成功')
}
// 获取值
const value = Reflect.get(target, key, receiver)
// 再次判断是否是对象
return reactive(value)
},
set(target, key, newValue, receiver) {
if (target[key] === newValue) return true
const keys = Reflect.ownKeys(target)
if (keys.includes(key)) {
// 有属性 改变值 改变视图
// target.key = newValue
} else {
// 增加属性
target[key] = newValue
}
updateView()
return Reflect.set(target, key, newValue, receiver)
},
// 删除操作
deleteProperty(target, key) {
delete target.key
updateView()
}
}
const proxy = new Proxy(obj, proxyConf)
return proxy
}
const data = {
name: 'haohao',
age: 20,
info: {
city: 'shangtou',
a: {
b: {
c: 100
}
}
},
test: "",
nums: [1, 2, 3, 4]
}
const proxy = reactive(data)
const content = document.querySelector('.content')
const but = document.querySelector('.but')
but.addEventListener('click', () => {
// console.log(proxy.name)
// console.log(proxy.info.a.b.c.d.e)
// proxy.sex = 123
// proxy.info.a.b.c.d.e = 23
// console.log(proxy.info.a.b.c.d.e)
// console.log(proxy)
})
</script>
</body>
</html>
优缺点
- 深度监听性能更好
- 可监听 新增 / 删除 属性
- 可监听数组变化
- Proxy 能规避 Object.defineProxy 的问题
- Proxy 无法兼容所有浏览器,无法 polyfill