js实现vue
使用原生 JavaScript 实现类似 Vue 的功能
原生 JavaScript 可以通过数据绑定、观察者模式和虚拟 DOM 等技术实现类似 Vue 的功能。以下是一个简化版的实现示例:
class MiniVue {
constructor(options) {
this.$options = options
this.$data = options.data()
this.$el = document.querySelector(options.el)
this.proxyData()
this.observe(this.$data)
this.compile(this.$el)
}
proxyData() {
for (let key in this.$data) {
Object.defineProperty(this, key, {
get() {
return this.$data[key]
},
set(newVal) {
this.$data[key] = newVal
}
})
}
}
observe(data) {
if (!data || typeof data !== 'object') return
Object.keys(data).forEach(key => {
let value = data[key]
const dep = new Dep()
Object.defineProperty(data, key, {
get() {
Dep.target && dep.addSub(Dep.target)
return value
},
set(newVal) {
if (newVal === value) return
value = newVal
dep.notify()
}
})
this.observe(value)
})
}
compile(el) {
const nodes = el.childNodes
nodes.forEach(node => {
if (node.nodeType === 1) {
this.compileElement(node)
} else if (node.nodeType === 3) {
this.compileText(node)
}
if (node.childNodes && node.childNodes.length) {
this.compile(node)
}
})
}
compileElement(node) {
const attrs = node.attributes
Array.from(attrs).forEach(attr => {
if (attr.name.startsWith('v-')) {
const dir = attr.name.substring(2)
const exp = attr.value
if (dir === 'model') {
this.handleModel(node, exp)
}
node.removeAttribute(attr.name)
}
})
}
compileText(node) {
const reg = /\{\{(.+?)\}\}/
const text = node.textContent
if (reg.test(text)) {
const exp = RegExp.$1.trim()
new Watcher(this, exp, (val) => {
node.textContent = text.replace(reg, val)
})
node.textContent = text.replace(reg, this[exp])
}
}
handleModel(node, exp) {
node.value = this[exp]
new Watcher(this, exp, (val) => {
node.value = val
})
node.addEventListener('input', (e) => {
this[exp] = e.target.value
})
}
}
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 = vm[exp]
Dep.target = null
}
update() {
const newVal = this.vm[this.exp]
if (newVal !== this.value) {
this.value = newVal
this.cb(newVal)
}
}
}
使用示例
<div id="app">
<input v-model="message">
<p>{{ message }}</p>
</div>
<script>
const app = new MiniVue({
el: '#app',
data() {
return {
message: 'Hello MiniVue!'
}
}
})
</script>
实现原理说明
-
数据代理:通过
proxyData方法将 data 中的属性代理到 Vue 实例上,可以直接通过this.xxx访问 data 中的属性 -
数据劫持:使用
Object.defineProperty对数据进行劫持,当数据变化时通知依赖更新 -
依赖收集:通过 Dep 类管理依赖,Watcher 类作为观察者,在数据变化时执行回调
-
模板编译:通过
compile方法解析模板,处理指令和插值表达式 -
双向绑定:
v-model指令实现了双向数据绑定,将输入框的值与数据进行关联
功能扩展方向
-
计算属性:可以添加 computed 选项,通过缓存计算结果优化性能
-
方法处理:添加 methods 选项,处理用户定义的方法
-
生命周期:实现 created、mounted 等生命周期钩子
-
组件系统:支持组件化开发,实现组件注册和嵌套
-
虚拟DOM:引入虚拟DOM提高渲染性能,实现更高效的DOM更新

这个实现展示了 Vue 的核心原理,实际 Vue 源码更为复杂,包含更多优化和功能。






