Skip to content

Instantly share code, notes, and snippets.

@cuongdevjs
Last active October 16, 2019 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cuongdevjs/b86afca5f4d0b4edc96fb4cacd842952 to your computer and use it in GitHub Desktop.
Save cuongdevjs/b86afca5f4d0b4edc96fb4cacd842952 to your computer and use it in GitHub Desktop.
Create own's Virtual DOM (update, create element)
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Gooact: Example #1">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
.btnRerender {
border: 1px solid red;
}
</style>
</head>
<body>
<div id="root"></div>
<div class="vdom"></div>
<button class="btnRerender">Re-render DOM</button>
<script id="jsbin-javascript">
/** @jsx h */
"use strict";
function h(type, props) {
for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
children[_key - 2] = arguments[_key];
}
return { type: type, props: props, children: children };
}
//? render to real DOM
var render = function render(node) {
console.log(node);
if (!node.type) {
return document.createTextNode(node);
}
var _parent = document.createElement(node.type);
node.children.map(function (_node) {
return render(_node);
}).forEach(function (_node) {
return _parent.appendChild(_node);
});
return _parent;
};
//? compare 2 node (old & new)
var isChange = function isChange(vOldNode, vNewNode) {
return typeof vOldNode !== typeof vNewNode || typeof vOldNode === "string" && vOldNode !== vNewNode || vOldNode.type !== vNewNode.type;
};
//? update to real DOM
var updateElement = function updateElement(parent, vNewNode, vOldNode) {
var index = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
// case vNewNode is text node
if (!vOldNode) {
console.log(vNewNode);
parent.appendChild(render(vNewNode));
} else if (!vNewNode) {
parent.removeChild(parent.childNodes[index]);
} else if (isChange(vOldNode, vNewNode)) {
parent.replaceChild(render(vNewNode), parent.childNodes[index]);
} else if (vNewNode.type) {
// case vNewNode is node
console.log(vNewNode);
for (var _idx = 0; _idx < vOldNode.children.length || _idx < vNewNode.children.length; _idx++) {
updateElement(parent.childNodes[_idx], vOldNode.children[_idx], vNewNode.children[_idx], _idx);
}
}
};
var oldVDOM = h(
"div",
{ "class": "parent" },
h(
"div",
null,
"1"
),
h(
"div",
null,
"2"
),
h(
"div",
null,
"3"
)
);
var newVDOM = h(
"div",
{ "class": "parent" },
h(
"div",
null,
"1"
),
h(
"div",
null,
"3"
),
h(
"div",
{ "class": "child" },
h(
"div",
null,
"5"
),
h(
"div",
null,
"6"
)
)
);
var _parent = document.getElementsByClassName("vdom")[0];
var _btn = document.getElementsByClassName("btnRerender")[0];
updateElement(_parent, oldVDOM);
_btn.addEventListener("click", function () {
updateElement(_parent, newVDOM, oldVDOM);
});
</script>
<script id="jsbin-source-javascript" type="text/javascript">/** @jsx h */
function h(type, props, ...children) {
return { type, props, children };
}
//? render to real DOM
const render = node => {
console.log(node);
if (!node.type) {
return document.createTextNode(node);
}
let _parent = document.createElement(node.type);
node.children
.map(_node => render(_node))
.forEach(_node => _parent.appendChild(_node));
return _parent;
};
//? compare 2 node (old & new)
const isChange = (vOldNode, vNewNode) => {
return (
typeof vOldNode !== typeof vNewNode ||
(typeof vOldNode === "string" && vOldNode !== vNewNode) ||
vOldNode.type !== vNewNode.type
);
};
//? update to real DOM
const updateElement = (parent, vNewNode, vOldNode, index = 0) => {
// case vNewNode is text node
if (!vOldNode) {
console.log(vNewNode);
parent.appendChild(render(vNewNode));
} else if (!vNewNode) {
parent.removeChild(parent.childNodes[index]);
} else if (isChange(vOldNode, vNewNode)) {
parent.replaceChild(render(vNewNode), parent.childNodes[index]);
} else if (vNewNode.type) {
// case vNewNode is node
console.log(vNewNode);
for (
let _idx = 0;
_idx < vOldNode.children.length || _idx < vNewNode.children.length;
_idx++
) {
updateElement(
parent.childNodes[_idx],
vOldNode.children[_idx],
vNewNode.children[_idx],
_idx
);
}
}
};
const oldVDOM = (
<div class="parent">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
);
const newVDOM = (
<div class="parent">
<div>1</div>
<div>3</div>
<div class="child">
<div>5</div>
<div>6</div>
</div>
</div>
);
const _parent = document.getElementsByClassName("vdom")[0];
const _btn = document.getElementsByClassName("btnRerender")[0];
updateElement(_parent, oldVDOM);
_btn.addEventListener("click", () => {
updateElement(_parent, newVDOM, oldVDOM);
})
</script></body>
</html>
/** @jsx h */
"use strict";
function h(type, props) {
for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
children[_key - 2] = arguments[_key];
}
return { type: type, props: props, children: children };
}
//? render to real DOM
var render = function render(node) {
console.log(node);
if (!node.type) {
return document.createTextNode(node);
}
var _parent = document.createElement(node.type);
node.children.map(function (_node) {
return render(_node);
}).forEach(function (_node) {
return _parent.appendChild(_node);
});
return _parent;
};
//? compare 2 node (old & new)
var isChange = function isChange(vOldNode, vNewNode) {
return typeof vOldNode !== typeof vNewNode || typeof vOldNode === "string" && vOldNode !== vNewNode || vOldNode.type !== vNewNode.type;
};
//? update to real DOM
var updateElement = function updateElement(parent, vNewNode, vOldNode) {
var index = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
// case vNewNode is text node
if (!vOldNode) {
console.log(vNewNode);
parent.appendChild(render(vNewNode));
} else if (!vNewNode) {
parent.removeChild(parent.childNodes[index]);
} else if (isChange(vOldNode, vNewNode)) {
parent.replaceChild(render(vNewNode), parent.childNodes[index]);
} else if (vNewNode.type) {
// case vNewNode is node
console.log(vNewNode);
for (var _idx = 0; _idx < vOldNode.children.length || _idx < vNewNode.children.length; _idx++) {
updateElement(parent.childNodes[_idx], vOldNode.children[_idx], vNewNode.children[_idx], _idx);
}
}
};
var oldVDOM = h(
"div",
{ "class": "parent" },
h(
"div",
null,
"1"
),
h(
"div",
null,
"2"
),
h(
"div",
null,
"3"
)
);
var newVDOM = h(
"div",
{ "class": "parent" },
h(
"div",
null,
"1"
),
h(
"div",
null,
"3"
),
h(
"div",
{ "class": "child" },
h(
"div",
null,
"5"
),
h(
"div",
null,
"6"
)
)
);
var _parent = document.getElementsByClassName("vdom")[0];
var _btn = document.getElementsByClassName("btnRerender")[0];
updateElement(_parent, oldVDOM);
_btn.addEventListener("click", function () {
updateElement(_parent, newVDOM, oldVDOM);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment