js 实现vue
Vue.js 的基本实现
在 JavaScript 中实现 Vue.js 的核心功能,主要包括数据响应式、模板编译和虚拟 DOM。以下是一个简化的实现示例。
数据响应式
使用 Object.defineProperty 或 Proxy 实现数据响应式。以下是一个基于 Object.defineProperty 的简单实现:
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();
}
});
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
观察者模式
实现一个简单的观察者(Watcher),用于更新视图:
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
Dep.target = this;
this.vm[this.key]; // 触发 getter
Dep.target = null;
}
update() {
this.cb.call(this.vm, this.vm[this.key]);
}
}
模板编译
实现一个简单的模板编译器,将模板转换为渲染函数:
function compile(template) {
const el = document.createElement('div');
el.innerHTML = template;
const fragment = document.createDocumentFragment();
while (el.firstChild) {
fragment.appendChild(el.firstChild);
}
return function render() {
return fragment.cloneNode(true);
};
}
虚拟 DOM
实现一个简化的虚拟 DOM 和 diff 算法:
function createElement(tag, props, children) {
return { tag, props, children };
}
function patch(oldNode, newNode) {
if (oldNode.tag !== newNode.tag) {
oldNode.el.parentNode.replaceChild(createEl(newNode), oldNode.el);
} else {
const el = (newNode.el = oldNode.el);
const oldProps = oldNode.props || {};
const newProps = newNode.props || {};
for (const key in newProps) {
if (newProps[key] !== oldProps[key]) {
el.setAttribute(key, newProps[key]);
}
}
for (const key in oldProps) {
if (!(key in newProps)) {
el.removeAttribute(key);
}
}
const oldChildren = oldNode.children || [];
const newChildren = newNode.children || [];
if (typeof newChildren === 'string') {
if (typeof oldChildren === 'string') {
if (newChildren !== oldChildren) {
el.textContent = newChildren;
}
} else {
el.textContent = newChildren;
}
} else {
if (typeof oldChildren === 'string') {
el.innerHTML = '';
newChildren.forEach(child => {
el.appendChild(createEl(child));
});
} else {
updateChildren(el, oldChildren, newChildren);
}
}
}
}
function updateChildren(parent, oldChildren, newChildren) {
const len = Math.max(oldChildren.length, newChildren.length);
for (let i = 0; i < len; i++) {
patch(oldChildren[i], newChildren[i]);
}
}
function createEl(vnode) {
if (typeof vnode === 'string') {
return document.createTextNode(vnode);
}
const el = document.createElement(vnode.tag);
for (const key in vnode.props) {
el.setAttribute(key, vnode.props[key]);
}
if (Array.isArray(vnode.children)) {
vnode.children.forEach(child => {
el.appendChild(createEl(child));
});
} else {
el.textContent = vnode.children;
}
return el;
}
整合实现
将以上部分整合为一个简单的 Vue 类:

class Vue {
constructor(options) {
this.$options = options;
this._data = options.data();
this.observe(this._data);
this.compile(options.template);
}
observe(data) {
for (const key in data) {
defineReactive(this, key, data[key]);
}
}
compile(template) {
const render = compile(template);
const vnode = render();
new Watcher(this, '_data', () => {
const newVnode = render();
patch(vnode, newVnode);
});
}
}
使用示例
const vm = new Vue({
data() {
return {
message: 'Hello, Vue!'
};
},
template: '<div>{{ message }}</div>'
});
注意事项
- 以上实现是一个简化的版本,实际 Vue.js 的实现更为复杂。
- 现代 Vue 3 使用
Proxy替代Object.defineProperty实现响应式。 - 虚拟 DOM 和 diff 算法在实际应用中需要更高效的实现。






