Skip to content

Instantly share code, notes, and snippets.

@muralikrishnat
Created March 3, 2017 10:32
Show Gist options
  • Save muralikrishnat/061c103477150483b30bf38e9d319431 to your computer and use it in GitHub Desktop.
Save muralikrishnat/061c103477150483b30bf38e9d319431 to your computer and use it in GitHub Desktop.
Concept of Virtual DOM
<!DOCTYPE html>
<html lang="en">
<head>
<title>Creating Virtual DOM</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="root"></div>
<script>
//method will generate unique string that helps us to tack dom elements
var getTimeStamp = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return 'U' + (new Date).getTime().toString(16) + s4() + s4();
};
var elemCache = {};
//Binding .data() fn to DOM elements to store data related to specific element
HTMLElement.prototype.data = function (key, val) {
var elem = this,
timeStamp = getTimeStamp();
if (!elem.N2Id) {
elem.N2Id = timeStamp;
}
if (!elemCache[elem.N2Id]) {
elemCache[elem.N2Id] = {};
}
if (!key && !val) {
return elemCache[elem.N2Id];
}
if (val) {
elemCache[elem.N2Id][key] = val;
} else {
return elemCache[elem.N2Id][key];
}
};
var VE = function (t, p, c) {
this.type = t;
this.props = p;
this.childItems = c;
};
//comparing nodes with new and old data.
//updating element inner html if there is any change in content
var compareNode = function (nodeToUpdate, srcNodeData, destNodeData) {
if (typeof srcNodeData.childItems === 'string') {
if (srcNodeData.childItems !== destNodeData.childItems) {
nodeToUpdate.innerHTML = srcNodeData.childItems;
}
}
if (srcNodeData.childItems instanceof Array) {
srcNodeData.childItems.forEach((t, i) => {
compareNode(nodeToUpdate.childNodes[i], t, destNodeData.childItems[i]);
});
}
};
//declaring vDOM object
var vDOM = {};
vDOM.render = function (elemObj, rootSelector) {
var elemToRender = document.querySelector(rootSelector);
if (elemToRender) {
var rootElem = document.createElement('DIV');
var vDOMObj = elemObj.renderFn();
if (!elemToRender.data('vDOM')) {
rootElem.appendChild(renderNode(vDOMObj));
elemToRender.data('vDOM', vDOMObj);
elemToRender.innerHTML = rootElem.innerHTML;
} else {
var oldDOM = elemToRender.data('vDOM');
compareNode(elemToRender.childNodes[0], vDOMObj, oldDOM);
}
}
};
var appMod = {
renderFn: function () {
//declaring our html as VE element
return new VE('div', { ttt: 'test' }, [
new VE('span', {}, 'This is Text Node ' + (new Date).toLocaleString()),
new VE('div', {}, 'This is static')
]);
}
};
var renderNode = function (vElem) {
var elem = document.createElement(vElem.type);
if (typeof vElem.childItems === 'string') {
elem.innerHTML = vElem.childItems;
} else {
Object.keys(vElem.props).forEach((p) => {
elem.setAttribute(p, vElem.props[p]);
});
if (vElem.childItems instanceof Array) {
vElem.childItems.forEach((c) => {
var cNode = renderNode(c);
elem.appendChild(cNode);
});
}
}
return elem;
};
var tick = function () {
vDOM.render(appMod, '#root');
};
window.onload = function () {
setInterval(tick, 1000);
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment