简易实现vue
简易 Vue 实现核心思路
创建一个极简的 Vue 实现需要理解其核心机制:数据响应式、模板编译和虚拟 DOM。以下是一个简化版实现框架,仅包含核心功能。
数据响应式系统
通过 Object.defineProperty 实现数据劫持,这是 Vue 2.x 的响应式原理基础:
class Observer {
constructor(data) {
this.walk(data)
}
walk(data) {
Object.keys(data).forEach(key => {
this.defineReactive(data, key, data[key])
})
}
defineReactive(obj, key, val) {
const dep = new Dep()
Object.defineProperty(obj, key, {
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
编译模板
实现最基础的模板编译功能,将 {{}} 语法转换为数据绑定:
function compile(el, vm) {
vm.$el = document.querySelector(el)
const fragment = document.createDocumentFragment()
let child
while (child = vm.$el.firstChild) {
fragment.appendChild(child)
}
function replace(frag) {
Array.from(frag.childNodes).forEach(node => {
const txt = node.textContent
const reg = /\{\{(.*?)\}\}/g
if (node.nodeType === 3 && reg.test(txt)) {
const arr = RegExp.$1.split('.')
let val = vm
arr.forEach(key => {
val = val[key]
})
node.textContent = txt.replace(reg, val).trim()
new Watcher(vm, RegExp.$1, newVal => {
node.textContent = txt.replace(reg, newVal).trim()
})
}
if (node.childNodes && node.childNodes.length) {
replace(node)
}
})
}
replace(fragment)
vm.$el.appendChild(fragment)
}
观察者实现
创建 Watcher 类来连接响应式数据和视图更新:
class Watcher {
constructor(vm, exp, cb) {
this.vm = vm
this.exp = exp
this.cb = cb
Dep.target = this
let val = vm
exp.split('.').forEach(key => {
val = val[key]
})
Dep.target = null
}
update() {
let val = this.vm
this.exp.split('.').forEach(key => {
val = val[key]
})
this.cb(val)
}
}
主类实现
组合以上功能创建 MiniVue 类:
class MiniVue {
constructor(options) {
this.$options = options
this._data = options.data
new Observer(this._data)
Object.keys(this._data).forEach(key => {
this._proxy(key)
})
compile(options.el, this)
}
_proxy(key) {
Object.defineProperty(this, key, {
configurable: true,
enumerable: true,
get: () => this._data[key],
set: val => {
this._data[key] = val
}
})
}
}
使用示例
这样实现的简易 Vue 可以这样使用:
<div id="app">
{{ message }}
</div>
<script>
new MiniVue({
el: '#app',
data: {
message: 'Hello Mini Vue!'
}
})
</script>
这个实现包含了 Vue 最核心的响应式系统、模板编译和依赖收集机制。实际 Vue 源码还包含虚拟 DOM diff、组件系统等更多复杂功能,但这个简化版已经展示了核心原理。







