JSFiddle - React, Tailwind, and code Playground
HTML
<div id="root"></div>
<script>
const vnode = create({
tag: 'div',
attrs: {class: "app"},
children: [
{tag: "h1", children: "Hi, %username%!"},
{tag: "button", attrs: {class: "button"}, children: "Enter"},
],
}, document.getElementById('root'));
</script>
CSS
.app {
text-align: center;
marging: 30px;
}
.button {
font-size: 30px;
}
JavaScript
//
// API
//
const TEXT_NODE = '#';
const R_IS_EVENT = /^on[A-Z]/;
const R_IS_TEXT = /string|number|boolean/;
const CLASS_ATTR = 'class';
const VALUE_ATTR = 'value';
function normalize(node) {
if (node == null) {
return {tag: TEXT_NODE, children: ''};
} else if (node.tag == null) {
return {tag: TEXT_NODE, children: node};
} else {
return node;
}
}
function create(/* Object */node, /* HTMLElement */parent) {
node = normalize(node); // "str" -> {tag: "#", children: "..."}
let el;
if (TEXT_NODE === node.tag) {
el = document.createTextNode(node.children);
} else {
el = document.createElement(node.tag);
updateAttrs(el, node.attrs); // добавляем аттрибуты
createChildren(node, el); // создаеём детишек
}
node.el = el; // запоминаем DOM
(parent !== null) && parent.appendChild(el);
return node;
}
function updateAttrs(/* HTMLElement */el, attrs, oldAttrs) {
let name;
let value;
for (name in attrs) {
value = attrs[name];
if (oldAttrs == null || oldAttrs[name] !== value) {
if (CLASS_ATTR === name) { // className
el.className = value;
}
else if (VALUE_ATTR === name) { // value
(el[name] !== value) && (el[name] = value);
}
else if (/^on[A-Z]/.test(name)) { // события
el.addEventListener(name.substr(2), value, false);
}
else { // все остальные
el.setAttribute(name, value);
}
}
}
if (oldAttrs != null) {
for (name in oldAttrs) {
value = oldAttrs[name];
if (attrs[name] == null && attrs[name] !== value) {
if (R_IS_EVENT.test(name)) {
el.removeEventListener(name.substr(2), value, false);
} else {
el.removeAttribute(name);
}
}
}
}
}
function createChildren(/* Object */node, /* HTMLElement */parent) {
const children = node.children;
const length = children.length;
if (length == null || R_IS_TEXT.test(typeof children)) {
node.children =...