模拟vue实现原理
模拟 Vue 实现原理
Vue.js 的核心原理包括数据响应式、虚拟 DOM、模板编译等。以下是一个简化版的模拟实现,重点展示数据响应式和虚拟 DOM 的基本概念。
数据响应式实现
通过 Object.defineProperty 或 Proxy 实现数据劫持,监听数据变化并触发更新。

class Observer {
constructor(data) {
this.walk(data);
}
walk(data) {
if (!data || typeof data !== 'object') return;
Object.keys(data).forEach(key => {
this.defineReactive(data, key, data[key]);
});
}
defineReactive(obj, key, val) {
const dep = new Dep();
this.walk(val); // 递归处理嵌套对象
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
Dep.target && dep.addSub(Dep.target);
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify(); // 通知所有订阅者更新
}
});
}
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Dep.target = null; // 全局唯一 Watcher
虚拟 DOM 与 Diff 算法
虚拟 DOM 是一个轻量级的 JavaScript 对象,描述真实 DOM 结构。Diff 算法用于高效更新 DOM。

class VNode {
constructor(tag, data, children, text) {
this.tag = tag;
this.data = data;
this.children = children;
this.text = text;
}
}
function createElement(tag, data, children) {
return new VNode(tag, data, children, undefined);
}
function createTextNode(text) {
return new VNode(undefined, undefined, undefined, text);
}
function patch(oldVnode, vnode) {
if (!oldVnode) {
// 首次渲染
return createElm(vnode);
} else {
// Diff 更新
if (oldVnode.tag === vnode.tag) {
const el = (vnode.el = oldVnode.el);
updateProps(el, oldVnode.data, vnode.data);
updateChildren(el, oldVnode.children, vnode.children);
} else {
// 替换节点
const parentEl = oldVnode.el.parentNode;
parentEl.removeChild(oldVnode.el);
parentEl.appendChild(createElm(vnode));
}
}
}
function createElm(vnode) {
if (vnode.text) {
return document.createTextNode(vnode.text);
}
const el = document.createElement(vnode.tag);
updateProps(el, {}, vnode.data);
vnode.children.forEach(child => {
el.appendChild(createElm(child));
});
vnode.el = el;
return el;
}
模板编译
将模板字符串转换为渲染函数,通常涉及解析、优化和代码生成三个阶段。
function compile(template) {
const ast = parse(template); // 解析为 AST
optimize(ast); // 静态节点标记
const code = generate(ast); // 生成渲染函数代码
return new Function(`with(this){return ${code}}`);
}
// 示例:简单插值解析
function parse(template) {
const tokens = template.split(/(\{\{\w+\}\})/);
const children = [];
tokens.forEach(token => {
if (token.match(/\{\{\w+\}\}/)) {
const key = token.slice(2, -2);
children.push({
type: 'interpolation',
key
});
} else if (token.trim()) {
children.push({
type: 'text',
value: token
});
}
});
return { children };
}
整合 Watcher 与更新机制
Watcher 作为观察者,连接响应式数据和视图更新。
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
const value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
function parsePath(path) {
const segments = path.split('.');
return function(obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) return;
obj = obj[segments[i]];
}
return obj;
};
}
完整流程示例
class MiniVue {
constructor(options) {
this.$options = options;
this._data = options.data;
new Observer(this._data);
this._proxyData();
this.$compile = compile(options.template);
new Watcher(this, 'render', this._update.bind(this));
}
_proxyData() {
Object.keys(this._data).forEach(key => {
Object.defineProperty(this, key, {
get() {
return this._data[key];
},
set(newVal) {
this._data[key] = newVal;
}
});
});
}
render() {
return this.$compile.call(this);
}
_update() {
const vnode = this.render();
patch(this._vnode, vnode);
this._vnode = vnode;
}
}
以上代码展示了 Vue 核心原理的简化实现,实际 Vue 源码更为复杂,包含更多优化和边界处理。






