Vue 2 响应式原理示例
这个示例展示了 Vue 2 中响应式系统的工作原理。下面将详细讲解代码中的各个部分,帮助理解 Vue 2 如何实现数据响应式。
1. 订阅者管理类 Dep
Dep
类用于管理依赖(订阅者),它包含以下几个关键部分:
subscribers
: 一个Set
集合,用于存储唯一的订阅者(更新函数)。depend()
: 添加当前的依赖到subscribers
集合中。notify()
: 通知所有订阅者调用其更新函数。
class Dep {
constructor() {
this.subscribers = new Set(); // 使用 Set 来存储订阅者,确保唯一性
}
// 添加订阅者
depend() {
if (Dep.target) {
this.subscribers.add(Dep.target); // 将当前依赖(更新函数)添加到订阅者集合
console.log(this.subscribers)
}
}
// 通知所有订阅者更新
notify() {
this.subscribers.forEach(sub => sub()); // 依次调用所有订阅者的更新函数
}
}
2. 当前活动的依赖 Dep.target
这是一个全局唯一的变量,用于存储当前的依赖(更新函数)。
Dep.target = null;
3. 将对象的属性转化为响应式 defineReactive
这个函数通过 Object.defineProperty
将对象的属性转换为响应式属性,定义了 getter
和 setter
:
- 在
getter
中,调用dep.depend()
进行依赖收集。 - 在
setter
中,调用dep.notify()
通知所有订阅者更新。
function defineReactive(obj, key) {
const dep = new Dep();
let val = obj[key];
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
dep.depend(); // 在 getter 中进行依赖收集
return val;
},
set(newVal) {
val = newVal;
dep.notify(); // 在 setter 中通知所有订阅者更新
}
});
}
4. 观察对象 observe
observe
函数遍历对象的每个属性,并调用 defineReactive
将其转换为响应式属性。
function observe(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key);
});
}
5. 自动运行并追踪依赖 autorun
autorun
函数接收一个更新函数 update
,并将其包装在 wrappedUpdate
中。在 wrappedUpdate
中:
- 设置当前的依赖为
wrappedUpdate
。 - 执行更新函数
update
以进行依赖收集。 - 清空当前的依赖。
function autorun(update) {
function wrappedUpdate() {
Dep.target = wrappedUpdate; // 设置当前活动的更新函数
update(); // 执行更新函数
Dep.target = null; // 清空当前活动的更新函数
}
wrappedUpdate(); // 初次执行,进行依赖收集
}
6. 示例使用
首先定义一个状态对象 state
,并使用 observe
函数将其转换为响应式对象。
const state = { message: '你好,宇珩', anotherMessage: '其他消息' };
observe(state);
定义更新函数:
updateMessage1
和updateMessage2
更新页面上的message
。updateAnother
更新页面上的anotherMessage
。
function updateMessage1() {
document.getElementById('message1').innerText = state.message;
}
function updateMessage2() {
document.getElementById('message2').innerText = state.message;
}
function updateAnother() {
document.getElementById('another').innerText = state.anotherMessage;
}
使用 autorun
函数自动追踪依赖并运行更新函数:
autorun(updateMessage1);
autorun(updateMessage2);
autorun(updateAnother);
最后,添加按钮点击事件以更新状态,从而触发响应式更新:
document.getElementById('updateBtn').addEventListener('click', () => {
state.message = '更新宇珩'; // 触发更新,调用 updateMessage1 和 updateMessage2
});
document.getElementById('updateAnotherBtn').addEventListener('click', () => {
state.anotherMessage = '其他更新'; // 触发更新,调用 updateAnother
});
总结
通过以上代码示例,我们详细讲解了 Vue 2 中响应式系统的基本原理和实现方法。这种响应式设计允许数据变化自动更新视图,极大地简化了前端开发过程。