手动实现vue视图
手动实现 Vue 视图的核心逻辑
Vue 的核心是数据驱动的视图渲染,通过响应式系统和虚拟 DOM 实现高效更新。以下是手动实现简化版 Vue 视图的关键步骤:
响应式数据绑定
通过 Object.defineProperty 或 Proxy 实现数据劫持,监听数据变化并触发更新:

function observe(data) {
if (!data || typeof data !== 'object') return;
Object.keys(data).forEach(key => {
let value = data[key];
const dep = new Dep(); // 依赖收集器
observe(value); // 递归劫持嵌套对象
Object.defineProperty(data, key, {
get() {
Dep.target && dep.addSub(Dep.target); // 收集当前 Watcher
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
observe(newVal); // 新值为对象时继续劫持
dep.notify(); // 触发更新
}
});
});
}
依赖收集与发布订阅
实现 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 = this.get(); // 触发 getter 收集依赖
Dep.target = null;
}
get() {
return this.exp.split('.').reduce((obj, key) => obj[key], this.vm);
}
update() {
const newValue = this.get();
if (newValue !== this.value) {
this.cb(newValue);
this.value = newValue;
}
}
}
模板编译
将模板转换为渲染函数,解析指令和插值表达式:

function compile(el, vm) {
const fragment = document.createDocumentFragment();
let child;
while (child = el.firstChild) {
fragment.appendChild(child);
}
function replace(node) {
const reg = /\{\{(.*?)\}\}/g;
if (node.nodeType === 3) {
const text = node.textContent;
if (reg.test(text)) {
const exp = RegExp.$1.trim();
new Watcher(vm, exp, value => {
node.textContent = text.replace(reg, value);
});
node.textContent = text.replace(reg, vm[exp]);
}
return;
}
if (node.nodeType === 1) {
Array.from(node.attributes).forEach(attr => {
if (attr.name.startsWith('v-')) {
const exp = attr.value;
if (attr.name === 'v-model') {
node.value = vm[exp];
new Watcher(vm, exp, value => {
node.value = value;
});
node.addEventListener('input', e => {
vm[exp] = e.target.value;
});
}
}
});
}
Array.from(node.childNodes).forEach(replace);
}
replace(fragment);
el.appendChild(fragment);
}
虚拟 DOM 与 Diff 算法
实现简化版虚拟 DOM 和差异比对:
function createElement(tag, props, children) {
return { tag, props, children };
}
function diff(oldNode, newNode) {
if (oldNode.tag !== newNode.tag) {
return node => {
const newEl = document.createElement(newNode.tag);
oldNode.el.parentNode.replaceChild(newEl, oldNode.el);
return newEl;
};
}
const patches = [];
const propsPatches = diffProps(oldNode.props, newNode.props);
if (propsPatches) {
patches.push(node => {
Object.entries(propsPatches).forEach(([k, v]) => {
node.setAttribute(k, v);
});
});
}
const childrenPatches = diffChildren(oldNode.children, newNode.children);
if (childrenPatches.length) {
patches.push(node => {
childrenPatches.forEach((patch, i) => {
patch(node.childNodes[i]);
});
});
}
return node => patches.forEach(patch => patch(node));
}
初始化入口
整合以上模块实现迷你 Vue 类:
class MiniVue {
constructor(options) {
this.$options = options;
this.$data = options.data();
observe(this.$data);
Object.keys(this.$data).forEach(key => {
Object.defineProperty(this, key, {
get() {
return this.$data[key];
},
set(newVal) {
this.$data[key] = newVal;
}
});
});
compile(options.el, this);
}
}
使用示例
<div id="app">
<input v-model="message">
<p>{{ message }}</p>
</div>
<script>
new MiniVue({
el: document.getElementById('app'),
data() {
return { message: 'Hello Vue' };
}
});
</script>
关键优化方向
- 批量异步更新:通过
nextTick实现更新队列 - 组件系统:支持嵌套组件和生命周期
- 指令扩展:实现
v-for、v-if等复杂指令 - 性能监控:添加渲染耗时统计
以上实现展示了 Vue 的核心原理,实际工程中还需处理边缘情况和性能优化。






