From 92eab0bf74cd4d6a405f01eaea3933dc19de76c8 Mon Sep 17 00:00:00 2001 From: hellerve Date: Thu, 20 Dec 2018 18:10:52 +0100 Subject: [PATCH] initial --- README.md | 4 +++ main.js | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 README.md create mode 100644 main.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..27b5c01 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# v + +An experiment in building a minimal virtual DOM, [following this little +tutorial](https://medium.com/@deathmood/how-to-write-your-own-virtual-dom-ee74acc13060). diff --git a/main.js b/main.js new file mode 100644 index 0000000..dbc5431 --- /dev/null +++ b/main.js @@ -0,0 +1,89 @@ +function setProp(t, n, v) { + if (isCProp(n)) return + else if (n === 'className') t.setAttribute('class', v); + else if (typeof value === 'boolean') setBProp(t, n, v); + else t.setAttribute(n, v); +} + +function unsetProp(t, n, v) { + if (isCProp(n)) return; + else if (n === 'className') t.removeAttribute('class'); + else if (typeof value === 'boolean') unsetBProp(t, n); + else t.removeAttribute(n); +} + + +function setBProp(t, n, v) { + if (v) t.setAttribute(n, v); + t[n] = !!v; +} + + +function unsetBProp(t, n) { + t.removeAttribute(n); + t[n] = false; +} + + +function isCProp(n) { + return isEProp(n) || name === 'forceUpdate'; +} + + +function isEProp(n) { + return /^on/.test(name); +} + + +function addEListeners(t, p) { + Object.keys(p).filter(isEProp).forEach(n => t.addEventListener(n.slice(2).toLowerCase(), p[name])); +} + + +function setProps(t, p) { + Object.keys(p).forEach(n => setProp(t, n, p[n])); +} + + +function updateProp(t, n, nv, ov) { + if (!nv) unsetProp(t, n, ov); + else if(!ov || nv !== ov) setProp(t, n, nv); +} + + +function updateProps(t, n, o = {}) { + const p = Object.assign({}, n, o); + Object.keys(p).forEach(nm => updateProp(t, nm, n[nm], o[nm]); +} + + +function createElement(n) { + if (typeof node === 'string') return document.createTextNode(n); + const e = document.createElement(n.type); + setProps(e, n.props); + addEListeners(e, n.props); + n.children.map(createElement).forEach(e.appendChild.bind(e)); + return e; +} + + +function changed(n, o) { + return typeof n !== typeof o || typeof n === 'string' && n !== o || n.type !== o.type || n.props.forceUpdate; +} + + +function updateElement(p, n, o, i=0) { + if (!o) p.appendChild(createElement(n)); + else if (!n) p.removeChild(p.childNodes[i]); + else if (changed(n, o)) p.replaceChild(createElement(n), p.childNodes[i]); + else if (n.type) { + updateProps(p.childNode[i], n.props, o.props); + for (let j = 0; j < Math.min(n.children.length, o.children.length); j++) { + updateElement(p.childNodes[i], n.children[j], o.children[j], j); + } + } +} + +function h(type, props, ...children) { + return { type, props: props || {}, children }; +}