Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vue.js-like Virtual DOM
<div id="app"></div>
<script>
// Create virtual node
function h(tag, props, children) {
// Return the virtual node
return {
tag,
props,
children,
}
}
// Mount a virtual node to the DOM
function mount(vnode, container) {
// Create the element
const el = (vnode.el = document.createElement(vnode.tag))
// Set properties
for (const key in vnode.props) {
el.setAttribute(key, vnode.props[key])
}
// Handle children
if (typeof vnode.children === 'string') {
el.textContent = vnode.children
} else {
vnode.children.forEach(child => {
mount(child, el)
})
}
// Mount to the DOM
container.appendChild(el)
}
// Unmount a virtual node from the DOM
function unmount(vnode) {
vnode.el.parentNode.removeChild(vnode.el)
}
// Take 2 virtual nodes, compare & figure out what's the difference
function patch(n1, n2) {
const el = (n2.el = n1.el)
// Case where the nodes are of different tags
if (n1.tag !== n2.tag) {
mount(n2, el.parentNode)
unmount(n1)
}
// Case where the nodes are of the same tag
else {
// New virtual node has string children
if (typeof n2.children === 'string') {
el.textContent = n2.children
}
// New virtual node has array children
else {
// Old virtual node has string children
if (typeof n1.children === 'string') {
el.textContent = ''
n2.children.forEach(child => mount(child, el))
}
// Case where the new vnode has string children
else {
const c1 = n1.children
const c2 = n2.children
const commonLength = Math.min(c1.length, c2.length)
// Patch the children both nodes have in common
for (let i = 0; i < commonLength; i++) {
patch(c1[i], c2[i])
}
// Old children was longer
// Remove the children that are not "there" anymore
if (c1.length > c2.length) {
c1.slice(c2.length).forEach(child => {
unmount(child)
})
}
// Old children was shorter
// Add the newly added children
else if (c2.length > c1.length) {
c2.slice(c1.length).forEach(child => {
mount(child, el)
})
}
}
}
}
}
// Create virtual nodes & render them below this line 👇
// Virtual node 1
const node1 = h('div', { class: 'container' }, [
h('h1', null, 'Hello World 🌍'),
h('p', null, 'Thanks for reading the marc.dev blog 😊'),
])
// Mount the node to the DOM
mount(node1, document.getElementById('app'))
// Virtual node 2
const node2 = h('div', { class: 'container' }, [
h('h1', null, 'Hello Dev 💻'),
h('p', null, [
h('span', null, 'Thanks for reading the '),
h('a', { href: 'https://marc.dev' }, 'marc.dev'),
h('span', null, ' blog'),
]),
h(
'img',
{
src: 'https://media.giphy.com/media/26gsjCZpPolPr3sBy/giphy.gif',
style: 'width: 350px; border-radius: 0.5rem;',
},
[],
),
])
// Patch the new node to the old node
setTimeout(() => {
patch(node1, node2)
}, 3000)
</script>
<div id="app"></app>
<script>
// Create virtual node
function h(tag, props, children) {
// Return the virtual node
}
// Mount a virtual node to the DOM
function mount(vnode, container) {
// Create the element
// Set props
// Handle children
// Mount to the DOM
}
// Unmount a virtual node from the DOM
function unmount(vnode) {
// Unmount the virtual node
}
// Take 2 vnodes, compare & figure out what's the difference
function patch(n1, n2) {
// Case where the nodes are of different tags
// Case where the nodes are of the same tag
// Case where the new vnode has string children
// Case where the new vnode has an array of vnodes
}
// Create virtual nodes & render them below this line...
</script>
@kisik21

This comment has been minimized.

Copy link

@kisik21 kisik21 commented May 12, 2020

Is this code licensed under an open-source license or is it public domain? I'd like to use it in my project, but not sure about the licensing and copyright.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.