Vue3 S3 - Mount, Patch
Vue
A simple renderer:
<div id="app"></div>
<script>
function h(tag, props, children) {
return {
tag,
props,
children,
};
}
function mount(vnode, container) {
const el = (vnode.el = document.createElement(vnode.tag));
// props
if (vnode.props) {
for (const key in vnode.props) {
const value = vnode.props[key];
el.setAttribute(key, value);
}
}
// children
if (vnode.children) {
if (typeof vnode.children === 'string') {
el.textContent = vnode.children;
} else {
vnode.children.forEach((child) => {
mount(child, el);
});
}
}
container.appendChild(el);
}
const vdom = h('div', {class: 'red'}, [h('span', null, 'hello')]);
mount(vdom, document.getElementById('app'));
function patch(n1, n2) {
if (n1.tag === n2.tag) {
const el = (n2.el = n1.el);
// props
const oldProps = n1.props || {};
const newProps = n2.props || {};
for (const key in newProps) {
const oldValue = oldProps[key];
const newValue = newProps[key];
if (newValue !== oldValue) {
el.setAttribute(key, newValue);
}
}
for (const key in oldProps) {
if (!key in newProps) {
el.removeAttribute(key);
}
}
// children
const oldChildren = n1.children;
const newChildren = n2.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) => {
mount(child, el);
});
} else {
// ...
}
}
} else {
// replace
}
}
const vdom2 = h('div', {class: 'green'}, [h('span', null, 'changed!')]);
patch(vdom, vdom2);
</script>