实现自己的vue
实现一个简易 Vue 框架
要实现一个类似 Vue 的响应式框架,需要理解其核心机制:数据劫持、依赖收集和派发更新。以下是关键实现步骤:
数据劫持(响应式系统)
使用 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)
连接响应式数据和视图更新:

class Watcher {
constructor(vm, key, cb) {
this.vm = vm
this.key = key
this.cb = cb
Dep.target = this
this.oldValue = vm[key] // 触发getter
Dep.target = null
}
update() {
const newValue = this.vm[this.key]
if (newValue !== this.oldValue) {
this.cb(newValue)
this.oldValue = newValue
}
}
}
编译器
解析模板并建立数据绑定:
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el)
this.vm = vm
this.compile(this.el)
}
compile(node) {
Array.from(node.childNodes).forEach(node => {
if (this.isElement(node)) {
this.compileElement(node)
} else if (this.isText(node)) {
this.compileText(node)
}
if (node.childNodes && node.childNodes.length) {
this.compile(node)
}
})
}
compileElement(node) {
Array.from(node.attributes).forEach(attr => {
if (this.isDirective(attr.name)) {
const dir = attr.name.substring(2)
this[dir] && this[dir](node, attr.value)
}
})
}
compileText(node) {
const reg = /\{\{(.*?)\}\}/
if (reg.test(node.textContent)) {
const key = RegExp.$1.trim()
this.update(node, key, 'text')
}
}
text(node, key) {
this.update(node, key, 'text')
}
model(node, key) {
this.update(node, key, 'model')
node.addEventListener('input', e => {
this.vm[key] = e.target.value
})
}
update(node, key, type) {
const updaterFn = this[type + 'Updater']
updaterFn && updaterFn(node, this.vm[key])
new Watcher(this.vm, key, value => {
updaterFn(node, value)
})
}
textUpdater(node, value) {
node.textContent = value
}
modelUpdater(node, value) {
node.value = value
}
isDirective(attr) {
return attr.startsWith('v-')
}
isElement(node) {
return node.nodeType === 1
}
isText(node) {
return node.nodeType === 3
}
}
整合框架
创建主类连接各模块:
class MyVue {
constructor(options) {
this.$options = options
this.$data = options.data
new Observer(this.$data)
this.proxyData(this.$data)
new Compiler(options.el, this)
}
proxyData(data) {
Object.keys(data).forEach(key => {
Object.defineProperty(this, key, {
get() {
return data[key]
},
set(newVal) {
data[key] = newVal
}
})
})
}
}
使用示例
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
const app = new MyVue({
el: '#app',
data: {
message: 'Hello MyVue!'
}
})
</script>
实现要点说明
- 响应式系统通过拦截对象属性的访问和修改来实现
- 每个响应式属性都有对应的 Dep 实例管理依赖
- Watcher 在初始化时会触发属性的 getter 进行依赖收集
- 数据变化时通过 setter 触发 Dep 的通知机制
- 编译器解析模板中的指令和插值表达式
- 通过代理将 data 的属性映射到 Vue 实例上
这个实现包含了 Vue 最核心的响应式原理,实际 Vue 还包含虚拟 DOM、组件系统等更多复杂功能,但以上代码已经展示了其最基础的工作机制。






