js 实现vue模板
实现 Vue 模板的核心思路
Vue 模板的核心是通过数据绑定和虚拟 DOM 实现动态渲染。以下是一个简化版的实现思路:
数据劫持与响应式
通过 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)
return value
},
set(newVal) {
if (newVal === value) return
value = newVal
observe(newVal)
dep.notify()
}
})
})
}
依赖收集系统
实现一个简单的发布-订阅模式:
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub => sub.update())
}
}
Dep.target = null
编译模板
将模板字符串解析为 AST 并生成渲染函数:
function compile(template) {
const ast = parse(template) // 简化的解析过程
return generate(ast) // 生成渲染函数
}
function parse(template) {
// 实现简单的标签和插值解析
const stack = []
let root
let currentParent
parseHTML(template, {
start(tag, attrs) {
const element = { tag, attrs, children: [] }
if (!root) {
root = element
} else if (currentParent) {
element.parent = currentParent
currentParent.children.push(element)
}
stack.push(element)
currentParent = element
},
end() {
stack.pop()
currentParent = stack[stack.length - 1]
},
chars(text) {
if (!currentParent) return
currentParent.children.push({
type: 3,
text
})
}
})
return root
}
虚拟 DOM 与渲染
实现一个简单的虚拟 DOM 和 patch 算法:
class VNode {
constructor(tag, data, children, text) {
this.tag = tag
this.data = data
this.children = children
this.text = text
}
}
function createElement(vnode) {
if (vnode.text) return document.createTextNode(vnode.text)
const el = document.createElement(vnode.tag)
vnode.data.attrs.forEach(attr => {
el.setAttribute(attr.name, attr.value)
})
vnode.children.forEach(child => {
el.appendChild(createElement(child))
})
return el
}
function patch(oldVnode, vnode) {
if (!oldVnode) {
return createElement(vnode)
}
// 简化的 diff 算法
if (oldVnode.tag !== vnode.tag) {
const parent = oldVnode.el.parentNode
parent.insertBefore(createElement(vnode), oldVnode.el)
parent.removeChild(oldVnode.el)
return
}
// 更新属性和子节点
updateAttrs(oldVnode, vnode)
updateChildren(oldVnode, vnode)
}
组件系统实现
实现基础的组件构造函数:
class Vue {
constructor(options) {
this.$options = options
this._data = options.data
observe(this._data)
this.$mount(options.el)
}
$mount(el) {
this.$el = document.querySelector(el)
const updateComponent = () => {
const vnode = this.$options.render.call(this)
patch(this._vnode, vnode)
this._vnode = vnode
}
new Watcher(this, updateComponent)
}
}
class Watcher {
constructor(vm, fn) {
this.vm = vm
this.getter = fn
this.get()
}
get() {
Dep.target = this
this.getter()
Dep.target = null
}
update() {
this.get()
}
}
使用示例
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
render() {
return new VNode('div', { attrs: [{ name: 'id', value: 'app' }] }, [
new VNode(null, null, null, this._data.message)
])
}
})
这个实现包含了 Vue 的核心功能:数据响应式、虚拟 DOM、模板编译和组件系统。实际 Vue 的实现更加复杂,包含更多优化和功能。







