自实现vue
自实现 Vue.js 的核心思路
实现一个简化版 Vue.js 需要理解其核心机制:数据响应式、虚拟 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());
}
}
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
Dep.target = this;
this.vm[this.key]; // 触发 getter 收集依赖
Dep.target = null;
}
update() {
this.cb.call(this.vm, this.vm[this.key]);
}
}
模板编译
将模板转换为渲染函数:
class Compiler {
constructor(el, vm) {
this.vm = vm;
this.el = document.querySelector(el);
this.compile(this.el);
}
compile(node) {
Array.from(node.childNodes).forEach(child => {
if (this.isElement(child)) {
this.compileElement(child);
} else if (this.isInterpolation(child)) {
this.compileText(child);
}
if (child.childNodes.length) this.compile(child);
});
}
isElement(node) {
return node.nodeType === 1;
}
isInterpolation(node) {
return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent);
}
compileText(node) {
const key = RegExp.$1.trim();
node.textContent = this.vm[key];
new Watcher(this.vm, key, val => {
node.textContent = val;
});
}
}
虚拟 DOM 与 Diff 算法
实现简单的虚拟 DOM 对比更新:
function createElement(tag, props, children) {
return { tag, props, children };
}
function patch(oldNode, newNode) {
if (oldNode.tag !== newNode.tag) {
oldNode.el.replaceWith(document.createElement(newNode.tag));
}
// 简化版属性/子节点对比
// ...
}
组件系统基础
实现组件注册和生命周期:

class Vue {
constructor(options) {
this.$options = options;
this.$data = options.data();
new Observer(this.$data);
this.proxyData();
new Compiler(options.el, this);
}
proxyData() {
Object.keys(this.$data).forEach(key => {
Object.defineProperty(this, key, {
get: () => this.$data[key],
set: val => (this.$data[key] = val)
});
});
}
}
使用示例
<div id="app">
{{ message }}
</div>
<script>
const vm = new Vue({
el: '#app',
data() {
return { message: 'Hello Vue!' };
}
});
</script>
优化方向
- 使用
Proxy替代Object.defineProperty解决数组监听问题 - 实现异步更新队列(nextTick)
- 完善事件系统和指令系统(如 v-model)
- 增加计算属性和侦听器功能
- 支持插槽和动态组件
这个简化实现涵盖了 Vue 的核心思想,实际框架需要考虑更多边界条件和性能优化。






