<meta name="description" content="vue3 deep dive">
<style>
.red {
color: red;
}
.green {
color: green;
}
</style>
<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]
// property attribute event listener
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')
])
function patch(n1, n2) {
// if (typeof n1 === 'string' && typeof n2 === 'string')
// return n2 = n1
// n2.dom = n1.dom
// if (n1.tag !== n2.tag) mount(n2, n1.parentNode)
// for (const key in n1.props) {
// if (n1.props[key] !== n2.props[key]) n2.dom.setAttribute(key, n2.props[key])
// }
// for (let i = 0; i < n1.children.length; i++) {
// patch(n1.children[i], n2.children[i])
// }
if (n1.tag === n2.tag) {
const el = n2.el = n1.el
// props
const oldProps = n1.props || {}
const newProps = n2.props || {}
// props value changed
for (const key in newProps) {
const oldValue = oldProps[key]
const newValue = newProps[key]
if (oldValue !== newValue) {
el.setAttribute(key, newValue)
}
}
// oldProps removed
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') {
el.textContent = newChildren
} else {
el.textContent = newChildren
}
} else {
if (typeof oldChildren === 'string') {
el.innerHTML = ''
newChildren.forEach(child => {
mount(child, el)
})
} else {
const commonLength = Math.min(oldChildren.length, newChildren.length)
for (let i = 0; i < commonLength; i++) {
patch(oldChildren[i], newChildren[i])
}
if (newChildren.length > oldChildren.length) {
newChildren.slice(oldChildren.length).forEach(child => {
mount(child, el)
})
} else if (newChildren.length < oldChildren.length) {
oldChildren.slice(newChildren.length).forEach(child => {
el.removeChild(child.el)
})
}
}
}
}
}
mount(vdom, document.querySelector('#app'))
const vdom2 = h('div', { class: 'green' }, [
h('span', null, 'changed!')
])
patch(vdom, vdom2)
</script>
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |