Vue.js 是通过其响应式系统来收集依赖的。1、数据劫持,2、依赖收集,3、依赖触发。Vue 使用了一个叫做 "依赖追踪" 的机制,通过监听数据的变化来自动更新视图。下面我们将详细介绍 Vue.js 是如何实现这一过程的。
一、数据劫持
Vue.js 使用 Object.defineProperty() 来劫持(或拦截)对象的属性。这使得 Vue.js 能够在属性被访问或修改时自动执行一些操作。
- 对象劫持:Vue.js 会遍历数据对象的所有属性,并使用 Object.defineProperty() 将这些属性转换为 getter 和 setter。
- 拦截操作:在 getter 中,Vue.js 会收集依赖;在 setter 中,Vue.js 会触发依赖。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
// 依赖收集
return val;
},
set(newVal) {
if (newVal !== val) {
val = newVal;
// 依赖触发
}
}
});
}
二、依赖收集
依赖收集是 Vue 响应式系统的核心部分。当访问数据属性时,Vue 会记录哪些组件依赖于这些属性,这样当属性发生变化时,Vue 可以知道哪些组件需要重新渲染。
- Dep 对象:每个响应式属性都有一个对应的 Dep 对象,用于存储依赖于该属性的 Watcher。
- Watcher 对象:每个组件对应一个 Watcher 对象,用于订阅属性的变化。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
constructor(vm, exp, cb) {
this.vm = vm;
this.exp = exp;
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
let value = this.vm[this.exp];
Dep.target = null;
return value;
}
update() {
let value = this.vm[this.exp];
let oldValue = this.value;
if (value !== oldValue) {
this.value = value;
this.cb.call(this.vm, value, oldValue);
}
}
}
三、依赖触发
当数据发生变化时,Vue 会触发依赖,并通知所有订阅了该属性变化的 Watcher 执行更新操作。
- 触发更新:在 setter 中,当数据发生变化时,会调用 Dep 的 notify 方法,通知所有的 Watcher。
- 更新组件:Watcher 收到通知后,会执行 update 方法,重新计算新值,并调用回调函数更新视图。
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(newVal) {
if (newVal !== val) {
val = newVal;
dep.notify();
}
}
});
}
四、实例说明
通过一个简单的实例,我们可以更清楚地看到 Vue 是如何收集依赖并触发更新的。
let data = { message: "Hello Vue!" };
defineReactive(data, 'message', data.message);
let vm = {
message: data.message
};
new Watcher(vm, 'message', (newVal, oldVal) => {
console.log(`Message changed from ${oldVal} to ${newVal}`);
});
data.message = "Hello World!";
// 控制台输出: Message changed from Hello Vue! to Hello World!
在这个实例中,当我们修改 data.message 时,Watcher 会被通知到,并输出相应的信息。这样,我们就实现了一个简单的响应式系统。
五、总结与建议
通过以上的介绍,我们了解了 Vue.js 是如何通过数据劫持、依赖收集和依赖触发来实现响应式系统的。这一机制使得 Vue.js 能够高效地管理数据和视图之间的关系,自动更新视图,减少手动操作的繁琐和错误。
为了更好地理解和应用 Vue.js 的依赖收集机制,建议读者:
- 深入学习 JavaScript 中的 Object.defineProperty() 方法。
- 了解设计模式中的观察者模式(Observer Pattern),因为 Vue.js 的响应式系统是这一模式的具体应用。
- 实践编写一些简单的响应式系统,逐步加深对依赖收集和触发机制的理解。
通过不断学习和实践,相信你会对 Vue.js 的响应式系统有更深刻的理解和掌握。
相关问答FAQs:
1. 什么是依赖收集?
依赖收集是Vue框架中的一个重要概念,用于追踪数据属性与视图之间的关联关系。当数据属性发生变化时,依赖收集会自动更新相关的视图。
2. Vue是如何收集依赖的?
Vue的依赖收集是通过观察者模式实现的。在Vue的内部,每个组件都有一个Watcher实例,它负责监听组件内部数据的变化。当组件初始化时,Vue会在模板中解析指令和表达式,并创建相应的Watcher实例。Watcher实例会将自身添加到被观察的数据属性的依赖列表中。
3. 依赖收集的工作原理是什么?
当Vue组件初始化完成后,Watcher实例会开始执行依赖收集的工作。依赖收集的过程包括以下几个步骤:
- 遍历模板中的所有指令和表达式,解析它们对应的数据属性。
- 在解析过程中,如果发现一个数据属性被使用,Watcher实例会将自身添加到该数据属性的依赖列表中。
- 如果该数据属性已经有其他Watcher实例监听,Watcher实例会将自身添加到该依赖列表中,如果没有,则创建一个新的依赖列表。
- 当数据属性发生变化时,被监听的Watcher实例会被通知,它们会执行相应的更新操作,更新视图。
通过这种方式,Vue实现了对数据属性与视图之间的绑定关系的自动追踪和更新。这使得开发者可以专注于数据的变化,而不需要手动去更新视图,提高了开发效率。
文章标题:vue是如何收集依赖的,发布者:不及物动词,转载请注明出处:https://worktile.com/kb/p/3655612