手动实现vue视图
手动实现 Vue 视图的核心逻辑
Vue 的视图更新依赖于数据劫持和依赖收集,通过监听数据变化触发视图更新。以下是简化版实现的核心步骤:
数据劫持(响应式系统)
使用 Object.defineProperty 或 Proxy 拦截数据访问和修改:

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(); // 触发更新
}
});
}
依赖收集与观察者
实现依赖收集器(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;
}
update() {
const value = this.get();
if (value !== this.value) {
this.cb.call(this.vm, value, this.value);
this.value = value;
}
}
get() {
return this.vm._data[this.exp]; // 简化版直接访问数据
}
}
模板编译
实现简单的模板解析和指令处理:
function compile(el, vm) {
const fragment = document.createDocumentFragment();
let child;
while ((child = el.firstChild)) {
fragment.appendChild(child);
}
function replace(frag) {
Array.from(frag.childNodes).forEach(node => {
if (node.nodeType === 3) { // 文本节点
const text = node.textContent;
const reg = /\{\{(.*?)\}\}/g;
if (reg.test(text)) {
const exp = RegExp.$1.trim();
new Watcher(vm, exp, newVal => {
node.textContent = text.replace(reg, newVal);
});
node.textContent = text.replace(reg, vm._data[exp]);
}
}
if (node.nodeType === 1) { // 元素节点
Array.from(node.attributes).forEach(attr => {
if (attr.name.startsWith('v-')) {
const exp = attr.value;
new Watcher(vm, exp, newVal => {
node.value = newVal; // 简化版仅处理v-model
});
node.addEventListener('input', e => {
vm._data[exp] = e.target.value;
});
node.value = vm._data[exp];
}
});
}
if (node.childNodes && node.childNodes.length) {
replace(node);
}
});
}
replace(fragment);
el.appendChild(fragment);
}
整合实现
创建 Vue 类整合上述功能:
class Vue {
constructor(options) {
this.$options = options;
this._data = options.data;
this.observe(this._data);
compile(options.el, this);
}
observe(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key]);
});
}
}
使用示例
<div id="app">
<input v-model="message">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue'
}
});
</script>
实现要点
- 响应式系统通过数据劫持实现自动依赖收集
- 每个数据属性对应一个 Dep 实例管理依赖
- 每个模板绑定对应一个 Watcher 实例触发更新
- 编译阶段解析模板并建立数据与视图的关联
以上实现省略了虚拟 DOM、组件系统等复杂功能,但展示了 Vue 响应式视图的核心原理。实际应用中还需考虑性能优化、生命周期管理等更多细节。






