vue实现mvvm思路
Vue 实现 MVVM 的思路
Vue 的 MVVM(Model-View-ViewModel)实现主要依赖于数据绑定和响应式系统。以下是其核心实现思路:
数据劫持与响应式
Vue 使用 Object.defineProperty 或 Proxy(Vue 3)劫持数据对象的属性,在属性被访问或修改时触发 getter 和 setter。通过依赖收集(Dep)和观察者(Watcher)机制,实现数据的响应式更新。
// 简化版数据劫持示例
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) return;
val = newVal;
dep.notify(); // 通知所有 Watcher 更新
}
});
}
模板编译
Vue 将模板解析为 AST(抽象语法树),并生成渲染函数。通过指令解析(如 v-model、v-for)和数据绑定,将模板中的动态部分与数据关联起来。
// 简化的模板编译示例
function compile(template) {
const ast = parse(template); // 解析为 AST
const code = generate(ast); // 生成渲染函数代码
return new Function(`with(this){return ${code}}`);
}
虚拟 DOM 与 Diff 算法
Vue 通过虚拟 DOM 优化渲染性能。数据变化时,生成新的虚拟 DOM,并通过 Diff 算法比对差异,最终高效更新真实 DOM。
// 简化的虚拟 DOM 示例
function createVNode(tag, data, children) {
return { tag, data, children };
}
function patch(oldVNode, newVNode) {
// Diff 算法实现
if (oldVNode.tag !== newVNode.tag) {
// 替换节点
} else {
// 更新属性或子节点
}
}
双向数据绑定
v-model 是语法糖,本质是 :value 和 @input 的组合。通过监听输入事件更新数据,再触发响应式系统更新视图。
// 简化的 v-model 实现
function bindModel(el, vm, exp) {
el.addEventListener('input', (e) => {
vm[exp] = e.target.value; // 数据更新
});
new Watcher(vm, exp, (value) => {
el.value = value; // 视图更新
});
}
依赖收集与派发更新
- Dep:管理依赖的容器,每个响应式属性对应一个 Dep。
- 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;
Dep.target = this;
this.value = vm[exp]; // 触发 getter,收集依赖
Dep.target = null;
}
update() {
const newValue = this.vm[this.exp];
if (newValue !== this.value) {
this.cb(newValue);
this.value = newValue;
}
}
}
总结
Vue 的 MVVM 实现核心包括:
- 数据劫持实现响应式。
- 模板编译生成渲染函数。
- 虚拟 DOM 优化渲染性能。
- 依赖收集与派发更新机制。
- 双向绑定语法糖简化开发。







