js实现vdom
实现虚拟DOM(Virtual DOM)的核心步骤
虚拟DOM的核心是通过JavaScript对象模拟真实DOM结构,通过对比新旧虚拟DOM树的差异,最小化操作真实DOM。以下是实现基础虚拟DOM的关键方法:
创建虚拟DOM节点
虚拟DOM节点是一个JavaScript对象,描述DOM元素的类型、属性和子节点。例如:
function createElement(type, props, ...children) {
return {
type,
props: props || {},
children: children.flat()
};
}
渲染虚拟DOM到真实DOM
将虚拟节点转换为真实DOM节点:

function render(vnode) {
if (typeof vnode === 'string') {
return document.createTextNode(vnode);
}
const node = document.createElement(vnode.type);
Object.entries(vnode.props || {}).forEach(([key, value]) => {
node.setAttribute(key, value);
});
(vnode.children || []).forEach(child => {
node.appendChild(render(child));
});
return node;
}
差异比较算法(Diff算法)
比较新旧虚拟DOM树的差异:
function diff(oldNode, newNode) {
if (!oldNode) return { type: 'CREATE', newNode };
if (!newNode) return { type: 'REMOVE' };
if (changed(oldNode, newNode)) return { type: 'REPLACE', newNode };
if (oldNode.type !== newNode.type) return { type: 'REPLACE', newNode };
const patches = [];
const propsPatches = diffProps(oldNode.props, newNode.props);
if (propsPatches) {
patches.push({ type: 'UPDATE_PROPS', props: propsPatches });
}
const childrenPatches = diffChildren(oldNode.children, newNode.children);
patches.push(...childrenPatches);
return patches.length ? { type: 'UPDATE', patches } : null;
}
应用差异到真实DOM
根据差异结果更新真实DOM:

function applyPatch(parent, patch, index = 0) {
const child = parent.childNodes[index];
switch (patch.type) {
case 'CREATE':
parent.appendChild(render(patch.newNode));
break;
case 'REMOVE':
parent.removeChild(child);
break;
case 'REPLACE':
parent.replaceChild(render(patch.newNode), child);
break;
case 'UPDATE':
patch.patches.forEach(p => {
if (p.type === 'UPDATE_PROPS') {
updateProps(child, p.props);
} else {
applyPatch(child, p);
}
});
break;
}
}
性能优化建议
使用key属性帮助识别节点:
// 在创建虚拟DOM时为可复用节点添加唯一key
createElement('ul', null,
items.map(item =>
createElement('li', { key: item.id }, item.text)
)
);
实现批处理更新:
let updateQueue = [];
let isUpdating = false;
function enqueueUpdate(update) {
updateQueue.push(update);
if (!isUpdating) {
isUpdating = true;
requestAnimationFrame(processUpdates);
}
}
function processUpdates() {
let patch;
while (patch = updateQueue.shift()) {
applyPatch(patch.parent, patch.patch, patch.index);
}
isUpdating = false;
}
完整示例流程
创建应用的基本结构:
// 1. 创建虚拟DOM
const vdom = createElement('div', { id: 'app' },
createElement('h1', null, 'Virtual DOM'),
createElement('ul', null,
createElement('li', { class: 'item' }, 'Item 1'),
createElement('li', { class: 'item' }, 'Item 2')
)
);
// 2. 渲染初始DOM
const dom = render(vdom);
document.body.appendChild(dom);
// 3. 创建新虚拟DOM
const newVdom = createElement('div', { id: 'app' },
createElement('h1', null, 'Updated Virtual DOM'),
createElement('ul', null,
createElement('li', { class: 'item' }, 'Item 1'),
createElement('li', { class: 'item active' }, 'Item 2')
)
);
// 4. 计算差异并应用更新
const patches = diff(vdom, newVdom);
applyPatch(dom.parentNode, patches);
这个实现展示了虚拟DOM的核心概念,实际生产环境中的库(如React)会有更复杂的优化和功能。






