October 04, 2018
Write a Javascript Library From Scratch
Almost every web developer has encountered use of jQuery in daily life coding. This post is about writing a custom javascript library from scratch to learn how we can create our own custom library like jquery.
It is going to be a simple library just to illustrate basic working model of jquery. First we are going to create an object and I am going to use $$ as object name. Let's start with definining our object using self-invoking function which accepts a selector as a parameter.
So what have we achieved so far now? We can select elements like jQuery using$$("p"), $$(window), $$(document) etc. Now that we can select element let's add some functions to our object using prototypes.
Notice that our prototype function each: does all the heavy lifting for library. What it actually does is it calls the other prototype function in from same prototype object. It then calls that function on every element present in object and passes three values (the current element, the object itself, current index). Now that our library is ready lets use it in our demo.
(function (win, doc) { function $$(selector) { // Initiate the object if it hasn't been initiated if (!(this instanceof $$)) { return new $$(selector); } this.length = 0; var elements = []; if(selector instanceof HTMLElement || selector == window || selector == document){ elements = [selector]; }else if(typeof selector === "string"){ elements = doc.querySelectorAll(selector); } // Push all elements to object if (elements.length) { this.length = elements.length; for (var i = 0; i < this.length; i++) { this[i] = elements[i]; } } return this; } // Append object to window object win.$$ = $$; })(window, document);
So what have we achieved so far now? We can select elements like jQuery using$$("p"), $$(window), $$(document) etc. Now that we can select element let's add some functions to our object using prototypes.
$$.prototype = { each: function (callback) { for (var i = 0; i < this.length; i++) { callback.call(this[i], this, i); } return this; }, ready:function(callback){ return this.each(function(){ win.addEventListener("DOMContentLoaded",callback,false); }); }, on: function (name, callback) { return this.each(function () { return this.addEventListener(name, callback, false); }); }, hide:function(speed,callback){ return this.each(function(ob){ return ob.css("display","none") && ob; }); }, show:function(speed,callback){ return this.each(function(ob){ return ob.css("display","block"); }); }, toggle:function(speed,callback){ return this.each(function(ob){ if(!ob.is(":visible")){ return ob.css("display","block"); }else{ return ob.css("display","none"); } }); }, is:function(prop){ switch(prop){ case ":visible": return this[0].clientHeight > 0 && this[0].clientWidth > 0 ? true : false; break; } }, css:function(param1,param2){ this.each(function(){ if(typeof param1 === "object"){ for(x in param1){ this.style[x] = param1[x]; } } else if(typeof param1 === "string" && typeof param2 === "string"){ this.style[param1] = param2; } }); return window.getComputedStyle(this[0]).getPropertyValue(param1); }, addClass:function(className){ return this.each(function(){ return this.classList.add(className); }); }, removeClass:function(className){ return this.each(function(){ return this.classList.remove(className); }); }, toggleClass:function(className){ return this.each(function(){ if(this.classList.contains(className)){ return this.classList.remove(className); }else{ return this.classList.add(className); } }); } };
Notice that our prototype function each: does all the heavy lifting for library. What it actually does is it calls the other prototype function in from same prototype object. It then calls that function on every element present in object and passes three values (the current element, the object itself, current index). Now that our library is ready lets use it in our demo.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Write a Javascript Library From Scratch - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<script type="text/javascript" src="js/library.js"></script>
<script type="text/javascript" src="js/javascript.js"></script>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<div class="mb-4">
<div>
<button class="btn btn-default btn-hide">Hide</button>
<button class="btn btn-default btn-show">Show</button>
<button class="btn btn-default btn-toggle">Toggle</button>
Hide, Show or Toggle paragraph below:
</div>
<div class="p-wrapper">
<p class="hide-show-toggle">
Aenean aliquam libero dolor, vel efficitur leo tempus sit amet. Aliquam erat volutpat. Ut malesuada leo id cursus congue.
Integer congue dolor ac risus laoreet, vitae fringilla dolor tempor. Nunc vitae rutrum elit.
Quisque dolor nulla, vulputate in mi vel, imperdiet tristique metus.
Integer sed ante vel ex elementum placerat sodales ut lectus. Integer sit amet posuere nulla.
Mauris eget lacinia est. Suspendisse laoreet euismod sollicitudin. Donec eu vehicula eros. Nunc mi magna, vestibulum sed scelerisque sed, consequat eu leo.
</p>
</div>
</div>
<div class="mb-4">
<div>
<button class="btn btn-default add-class">Add Class</button>
<button class="btn btn-default remove-class">Remove Class</button>
<button class="btn btn-default toggle-class">Toggle Class</button>
Add, Remove or Toggle class on paragraph below:
</div>
<p class="add-remove-toggle">
Morbi felis diam, ornare et lorem sed, accumsan fermentum nunc.
Fusce elementum auctor tortor vitae hendrerit. Nunc a tincidunt velit. Duis nec ornare ante, at ullamcorper massa.
Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam nisl dolor, dapibus eu sollicitudin id, ornare fermentum odio.
Curabitur laoreet enim enim, a elementum nisl ornare eget. Ut lectus sem, mollis vitae augue ut, consectetur mattis augue. Etiam vel placerat nisi, quis consectetur magna.
Sed a condimentum ipsum. Phasellus non nisi augue. Donec venenatis metus vel laoreet varius. Curabitur elit risus, vulputate ut sagittis a, placerat quis quam.
</p>
</div>
</div>
</body>
</html>
style.css
*{
box-sizing: border-box;
}
html,body{
margin: 0;
padding: 0;
}
body{
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
a{
text-decoration: none;
color: #3778cd;
}
.container{
max-width: 1140px;
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
.mb-4{
margin-bottom: 1rem;
}
.btn{
display: inline-block;
padding: 5px 10px;
cursor: pointer;
font: inherit;
background: #fff;
border: 1px solid #eee;
}
.bg-color {
background: #006cad;
color: #fff;
}
javascript.js
$$(document).ready(function(){
$$(".btn-hide").on("click",function(){
$$(".hide-show-toggle").hide();
});
$$(".btn-show").on("click",function(){
$$(".hide-show-toggle").show();
});
$$(".btn-toggle").on("click",function(){
$$(".hide-show-toggle").toggle();
});
$$(".add-class").on("click",function(){
$$(".add-remove-toggle").addClass("bg-color");
});
$$(".remove-class").on("click",function(){
$$(".add-remove-toggle").removeClass("bg-color");
});
$$(".toggle-class").on("click",function(){
$$(".add-remove-toggle").toggleClass("bg-color");
});
});