做公司网站别人能看到吗,建设个公司网站需要多少费用,wordpress忘记密码,儿童教育网站怎么做有趣Vue 3 带来了许多令人兴奋的新特性和改进#xff0c;其中之一就是其双向数据绑定的实现方式。与 Vue 2 使用 Object.defineProperty 不同#xff0c;Vue 3 利用了 JavaScript 的 Proxy 特性来创建响应式数据。在这篇博客中#xff0c;我们将探讨 Vue 3 中双向数据绑定的基础…Vue 3 带来了许多令人兴奋的新特性和改进其中之一就是其双向数据绑定的实现方式。与 Vue 2 使用 Object.defineProperty 不同Vue 3 利用了 JavaScript 的 Proxy 特性来创建响应式数据。在这篇博客中我们将探讨 Vue 3 中双向数据绑定的基础原理并尝试手动实现一个简化版的这一机制。
核心概念
Vue 3 的双向绑定依赖于两个核心概念响应式代理Reactive Proxy 和 Effect 依赖收集系统。
响应式代理
Vue 3 使用 Proxy 对象来创建响应式数据。这允许框架在不改变对象本身结构的情况下拦截并跟踪属性的访问和修改。
Effect 依赖收集系统
Effect 依赖收集系统用于自动追踪响应式数据的使用情况并在数据变化时重新执行副作用如渲染函数。
实现步骤
以下是手动实现 Vue 3 双向绑定的简化步骤
1. 创建 reactive 函数
这个函数用于将普通对象转换为响应式代理。
function reactive(target) {// 使用 Proxy 对象创建响应式数据return new Proxy(target, {// 拦截对象属性的读取get(target, key, receiver) {console.log(访问了属性${key});// 使用 Reflect.get 保证 this 指向正确return Reflect.get(target, key, receiver);},// 拦截对象属性的设置set(target, key, value, receiver) {console.log(设置了属性${key}新值为${value});// 使用 Reflect.set 设置属性值Reflect.set(target, key, value, receiver);// 此处省略了依赖通知逻辑实际 Vue 3 中会触发更新return true;}});
}2. 定义 effect 函数
effect 函数用于注册副作用函数并在响应式数据变化时执行这些函数。
let activeEffect null;function effect(fn) {// 设置当前活动的副作用函数activeEffect fn;// 立即执行函数用于依赖收集fn();// 重置当前活动的副作用函数activeEffect null;
}
3. 改进 reactive 以收集依赖
现在我们需要修改 reactive 函数以支持依赖收集和派发更新。
const targetMap new WeakMap();function track(target, key) {// 如果没有活动的副作用函数直接返回if (!activeEffect) return;// 从 targetMap 中获取当前对象的所有依赖let depsMap targetMap.get(target);if (!depsMap) {// 如果没有就创建新的 Map 并存入 targetMaptargetMap.set(target, (depsMap new Map()));}// 获取当前属性的所有依赖let dep depsMap.get(key);if (!dep) {// 如果没有就创建新的 Set 并存入 depsMapdepsMap.set(key, (dep new Set()));}// 将当前活动的副作用函数添加到依赖集合中dep.add(activeEffect);
}function trigger(target, key) {// 从 targetMap 中获取对象的所有依赖const depsMap targetMap.get(target);if (!depsMap) return;// 获取当前属性的所有依赖let dep depsMap.get(key);if (dep) {// 对于每一个依赖即副作用函数执行它dep.forEach(effect effect());}
}// 更新 reactive 函数
function reactive(target) {return new Proxy(target, {// 拦截属性读取get(target, key, receiver) {// 收集依赖track(target, key);return Reflect.get(target, key, receiver);},// 拦截属性设置set(target, key, value, receiver) {// 设置属性值Reflect.set(target, key, value, receiver);// 触发更新trigger(target, key);return true;}});
}4. 测试实例
创建一个响应式对象并观察它的变化。
const state reactive({ count: 0 });// 注册一个副作用函数来模拟渲染逻辑
effect(() {console.log(count is now: ${state.count});
});// 更改响应式数据的属性触发副作用函数
state.count;
完整代码
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleVue 3 简易双向数据绑定测试/title
/head
bodyh1Vue 3 简易双向数据绑定测试/h1div idapppCount: span idcount0/span/pbutton idincrementIncrement/button/divscript// reactive 函数function reactive(target) {const handler {get(target, key, receiver) {track(target, key);return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {Reflect.set(target, key, value, receiver);trigger(target, key);return true;}};return new Proxy(target, handler);}let activeEffect null;function effect(fn) {activeEffect fn;fn();activeEffect null;}const targetMap new WeakMap();function track(target, key) {if (!activeEffect) return;let depsMap targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap new Map()));}let dep depsMap.get(key);if (!dep) {depsMap.set(key, (dep new Set()));}dep.add(activeEffect);}function trigger(target, key) {const depsMap targetMap.get(target);if (!depsMap) return;let dep depsMap.get(key);if (dep) {dep.forEach(effect effect());}}// 测试代码const state reactive({ count: 0 });effect(() {document.getElementById(count).innerText state.count;});document.getElementById(increment).addEventListener(click, () {state.count;});/script
/body
/html在这个文件中我们创建了一个按钮每当它被点击时就会增加 state.count 的值。这个值的变化会触发绑定的副作用函数从而更新显示在页面上的计数结论
小结
以上代码展示了一个 Vue 3 中双向数据绑定的简化实现。通过 Proxy 和动态依赖收集系统我们可以创建一个灵活且强大的响应式系统。这种实现方式使得 Vue 3 在处理复杂应用时更为高效和灵活。