Supongo que no soy el único que empezó a usar JavaScript por medio de jQuery. La librería jQuery ha sido crucial para el desarrollo en Front, nos ha permitido a los desarrolladores hacer casi todo lo que queríamos de una manera rápida, sencilla y sin preocuparse por los navegadores. El único inconveniente que tenía era que debíamos de cargar la librería, que no era especialmente ligera, y que ralentizaba la carga y uso de la web en cuestión.
Gracias al desarrollo del JavaScript «a pelo» (llamado Vanilla JS, o Plain JS) ahora ya podemos prescindir de jQuery y seguir disfrutando de la facilidad de uso, pero aún así a mi me está costando dar el salto de jQuery a VanillaJS, y es que son ya muchos años trabando del modo jQuery.
Para intentar aliviar este cambio, he recopilado una sería de funciones que ya usaba de manera recursiva en jQuery, que hacen que mi código JS sea más limpio y asemejarlo un poco más a mi quería librearía.
He juntado todas ellas (y otras que vendrán) en un fichero que enlazo en mis proyectos, y así puedo hacer referencia a estas funciones a lo largo de todo el proyecto.
<script src="/js/plainJS.js" />
Seleccionar elementos del DOM
Esta es una de las tareas que más veces debemos de hacer, y con jQuery era tan sencillo como usar la función $. Ahora con Javascript podemos hacer uso de toda esta potencia por medio de document.querySelector y document.querySelectorAll, pero debemos de escribir muchos caracteres cada vez que queremos usarlo. Por eso podemos crear una función $ y $1 (o como tu quieras llamarla) que te haga ser más eficiente.
// Seleccionar una lista de elementos por medio de un selector CSS. El contexto es opcional function $(selector, context) { return (context || document).querySelectorAll(selector); } // Seleccionar el primer elemento que tenga el selector CSS. El contexto es opcional: function $1(selector, context) { return (context || document).querySelector(selector); }
Ejemplos:
// Seleccionar todos los elementos '.bar' dentro de contenedores '.foo' var elems = $('.foo .bar'); // ejemplo con contexto var container = $1('.foo'); // seleccionar elementos '.bar' dentro del contenedor var elems = $('.bar', container);
Añadir, eliminar y comprobar clases
function hasClass(el, className) { return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); } function addClasses(el, classesArray) { if ( classesArray instanceof Array ) { for ( var i = 0; i < classesArray.length; i++ ) { addClass(el, classesArray[i]); } } else { addClass(el, classesArray); } } function addClass(el, className) { if ( el ) { if ( el.tagName ) { doAddClass(el, className); } else if ( el.length >= 1 ) { for ( var i = 0; i < el.length; i++ ) { doAddClass(el[i], className); } } } } function removeClasses(el, classesArray) { if ( classesArray instanceof Array ) { for ( var i = 0; i < classesArray.length; i++ ) { removeClass(el, classesArray[i]); } } else { removeClass(el, classesArray); } } function removeClass(el, className) { if ( el ) { if ( el.tagName ) { doRemoveClass(el, className); } else if ( el.length >= 1 ) { for ( var i = 0; i < el.length; i++ ) { doRemoveClass(el[i], className); } } } } function doAddClass(el, className) { if (el.classList) { el.classList.add(className); } else if (!hasClass(el, className)) { el.className += ' ' + className; } } function doRemoveClass(el, className) { if (el.classList) el.classList.remove(className); else el.className = el.className.replace(new RegExp('\\b'+ className+'\\b', 'g'), ''); } function toggleClass(el, className) { if ( hasClass(el, className) ) { removeClass(el, className); return false; } else { addClass(el, className); return true; } }
Ejemplos:
var el = document.querySelector('div'); if (!hasClass(el, 'foo')){ addClass(el, 'foo'); }
Manipular el DOM
function appendTo(wrap, newElem) { wrap.insertAdjacentHTML( 'beforeend', newElem); } function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } // document.getElementById("my-element").remove(); Element.prototype.remove = function() { this.parentElement.removeChild(this); }; // document.getElementsByClassName("my-elements").remove(); NodeList.prototype.remove = HTMLCollection.prototype.remove = function() { for(var i = this.length - 1; i >= 0; i--) { if(this[i] && this[i].parentElement) { this[i].parentElement.removeChild(this[i]); } } }; // know if parents has a selector // var parents = getParents(elem, '.some-class'); // var allParents = getParents(elem.parentNode); var getParents = function ( elem, selector ) { // Element.matches() polyfill if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function(s) { var matches = (this.document || this.ownerDocument).querySelectorAll(s), i = matches.length; while (--i >= 0 && matches.item(i) !== this) {} return i > -1; }; } // Setup parents array var parents = []; // Get matching parent elements for ( ; elem && elem !== document; elem = elem.parentNode ) { // Add matching parents to array if ( selector ) { if ( elem.matches( selector ) ) { parents.push( elem ); } } else { parents.push( elem ); } } return parents; };
Obtener posición
function offset(el, parentElem) { var rect = el.getBoundingClientRect(), scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, scrollTop = window.pageYOffset || document.getElementById(parentElem).scrollTop || document.documentElement.scrollTop; return { top: rect.top + scrollTop, left: rect.left + scrollLeft } }
Ocultar o mostrar elementos
function hide(el) { el.style.display = 'none'; } function show(el, value) { el.style.display = value; } function toggleVisibility(el, value) { var display = (window.getComputedStyle ? getComputedStyle(el, null) : el.currentStyle).display; if (display == 'none') el.style.display = value; else el.style.display = 'none'; }
Ejemplos:
hide( elem ); show( elem, 'block' ); toggleVisibility( elem, 'block' );
Poner estilos CSS a un elemento
function css(el, styles) { for (var property in styles) { el.style[property] = styles[property]; } }
Ejemplos:
var el = document.querySelector('div'); css(el, { background: 'green', display: 'none', 'border-radius': '5px' });
Animar una propiedad del elemento
// fade an element from the current state to full opacity in "duration" ms function fadeOut(el, duration) { var s = el.style, step = 25/(duration || 300); s.opacity = s.opacity || 1; (function fade() { if ( ( s.opacity -= step) &amp;amp;amp;amp;lt; 0 ) { s.display = "none"; } else { setTimeout(fade, 25); } })(); } // fade out an element from the current state to full transparency in "duration" ms // display is the display style the element is assigned after the animation is done function fadeIn(el, duration, display) { var s = el.style, step = 25/(duration || 300); s.opacity = s.opacity || 0; s.display = display || "block"; (function fade() { if ( ( s.opacity = parseFloat(s.opacity)+step) &amp;amp;amp;amp;gt; 1 ) { s.opacity = 1; } else { setTimeout(fade, 25); } })(); }
Ejemplos:
fadeOut(elem, 500); fadeIn(elem, 500);
Peticiones Ajax
function getAjax(url, success) { var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); xhr.open('GET', url); xhr.onreadystatechange = function() { if (xhr.readyState>3 && xhr.status==200) success(xhr.responseText); }; //xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.send(); return xhr; } function getCORS(url, success) { var xhr = new XMLHttpRequest(); if (!('withCredentials' in xhr)) xhr = new XDomainRequest(); // fix IE8/9 xhr.open('GET', url); xhr.onload = success; xhr.send(); return xhr; } function postAjax(url, data, success) { // example request // postAjax('http://foo.bar/', 'p1=1&p2=Hello+World', function(data){ console.log(data); }); // example request with data object // postAjax('http://foo.bar/', { p1: 1, p2: 'Hello World' }, function(data){ console.log(data); }); var params = typeof data == 'string' ? data : Object.keys(data).map( function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) } ).join('&'); var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); xhr.open('POST', url); xhr.onreadystatechange = function() { if (xhr.readyState>3 && xhr.status==200) { success(xhr.responseText); } }; //xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(params); return xhr; }
Ejemplos:
getAjax('http://foo.bar/?p1=1&amp;amp;amp;amp;amp;p2=Hello+World', function(respone){ var jsonData = JSON.parse(respone); console.log(respone); console.log(jsonData); }); // example request postAjax('http://foo.bar/', 'p1=1&amp;amp;amp;amp;amp;p2=Hello+World', function(data){ console.log(data); }); // example request with data object postAjax('http://foo.bar/', { p1: 1, p2: 'Hello World' }, function(data){ console.log(data); });
Mergear dos objetos
function extend(obj, src) { Object.keys(src).forEach(function(key) { obj[key] = src[key]; }); return obj; }
Crear, obtener y borrar Cookies
function getCookie(name) { var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); return v ? v[2] : null; } function setCookie(name, value, days) { var d = new Date(); d.setTime(d.getTime() + 24*60*60*1000*days); document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString(); } function deleteCookie(name) { setCookie(name, '', -1); }
Más información
También puedes consultar otras webs que tratan esta transición dulce con más profundidad:
- Código alternativo a jQuery: http://youmightnotneedjquery.com/
- Funciones y plugins hechos con Javascript: https://plainjs.com/
- Native JavaScript Equivalents of jQuery Methods