欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > vue 双向绑定原理

vue 双向绑定原理

2024/10/24 20:24:00 来源:https://blog.csdn.net/Gary_888/article/details/140835036  浏览:    关键词:vue 双向绑定原理

响应式原理

Vue的核心特性之一,数据驱动视图,修改了数据之后视图随之响应更新。
Vue2是借助Object.defineProperty()实现的,而Vue3是借助proxy实现的,Proxy相比Object.defineProperty在处理数组和新增属性的响应式处理上更加方便。

双向绑定

Vue2的双向绑定是通过数据劫持结合发布/订阅模式实现的。数据响应系统的核心是观察者模式(Observer)订阅者(Dep)模式。

1. 数据劫持

Vue 通过递归遍历数据对象的所有属性,并使用Object.defineProperty方法将每个属性转换为getter/setter形式。这使得当数据属性被访问或修改时,可以触发相应的回调函数。

实现步骤:

  1. 创建Observer对象:当一个Vue实例被创建时,它会调用new Observer(value)来将数据对象转换为响应式。Observer类负责将对象的每个属性都转换为getter/setter。
  2. 定义getter和setter:对于每个属性,Observer会在属性的Object.defineProperty中定义gettersetter
  • getter:当访问属性时,getter会记录当前的依赖关系。
  • setter:当属性被修改时,setter会通知所有的依赖者更新。
  1. 递归处理嵌套属性:如果属性值是一个对象,那么会递归调用Observer类来继续转换内部属性。

2.发布/订阅模式

Vue使用了发布/订阅模式来管理依赖关系。每个数据属性都有一个对应的Dep对象,它负责收集所有依赖该属性的观察者(Watcher)

实现步骤:

  1. 创建Dep对象:当Observer创建getter时,会为每个属性创建一个Dep实例。
  2. 收集依赖:当渲染视图时,Watcher会自动收集依赖。这是通过在渲染过程中调用Dep.target来实现。
  3. 更新依赖:当属性值发生变化时,Dep会通知所有相关的Watcher更新。

3.Watcher对象

Watcher对象负责更新视图。每当一个属性被访问时,就会创建一个Watcher实例。当属性发生变化时,Watcher就会被Dep通知,从而触发更新视图的操作。

实现步骤:

  1. 创建Watcher实例:在渲染过程中,每当一个属性被访问,就会创建一个新的Watcher实例。
  2. 收集依赖:Watcher会自动收集依赖,也就是将自身添加到Dep的依赖列表中。
  3. 更新视图:当属性值发生变化时,Watcher会收到通知并执行更新逻辑。

示例代码

function observe(value) {if (!value || typeof value !== 'object') {return;}let ob = new Observer(value);
}function Observer(value) {this.value = value;this.walk(value);
}Observer.prototype.walk = function (obj) {const keys = Object.keys(obj);for (let i = 0; i < keys.length; i++) {defineReactive(obj, keys[i]);}
};function defineReactive(obj, key) {let val = obj[key];observe(val); // 递归处理嵌套属性const dep = new Dep();Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {if (Dep.target) {dep.addSub(Dep.target);}return val;},set: function reactiveSetter(newVal) {if (newVal === val) {return;}val = newVal;observe(newVal); // 递归处理新赋值dep.notify(); // 通知依赖更新}});
}function Dep() {this.subs = [];
}Dep.prototype.addSub = function (sub) {this.subs.push(sub);
};Dep.prototype.notify = function () {this.subs.forEach(sub => sub.update());
};// Watcher 示例
function Watcher(vm, expression, callback) {this.vm = vm;this.expression = expression;this.callback = callback;Dep.target = this;this.value = this.get();Dep.target = null;
}Watcher.prototype.get = function () {return this.vm[this.expression];
};Watcher.prototype.update = function () {const newValue = this.vm[this.expression];const oldValue = this.value;if (newValue !== oldValue) {this.callback(newValue, oldValue);}
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com