10 consejos para escribir JavaScript sin jQuery

jQuery es una gran biblioteca. Llegó a ser en la época en que IE6 era el navegador número uno. En aquel entonces, había peculiaridades y diferencias que eran tediosas de solucionar y jQuery era la herramienta perfecta para escribir código entre navegadores.

Hoy, sin embargo, los navegadores web han avanzado mucho desde aquellos días. Podemos utilizar cómodamente todas las funciones proporcionadas por ES5, y tenemos a nuestra disposición increíbles API de HTML5 que hacen que trabajar con el DOM sea mucho más agradable. Los desarrolladores ahora se encuentran en una posición en la que pueden optar por omitir jQuery para algunos proyectos y aún así conservar su productividad.

No me malinterpreten:jQuery sigue siendo una biblioteca maravillosa y, en la mayoría de los casos, será mejor que la use. Sin embargo, para cosas más pequeñas como páginas simples con interacciones limitadas de JS, extensiones de navegador y sitios móviles, puede usar Vanilla JS. Aquí hay 10 consejos que te ayudarán en tu esfuerzo.

1. Escuchando Documento Listo

Lo primero que hace cuando escribe jQuery es envolver su código en un $(document).ready() llamada, para que sepa cuándo el DOM está listo para la manipulación. Sin jQuery, tenemos el evento DOMContentLoaded. Así es como se usa:

// Add an event listener of DOMContentLoaded to the whole document and call an anonymous function.
// You can then wrap your code in that function's brackets
// and it will execute once loading is complete.

document.addEventListener('DOMContentLoaded', function () {

    // Our hawaiian greeting is displayed as soon as the page loads,

    console.log('Aloha');

});

2. Selección de elementos

Érase una vez, solo podíamos seleccionar elementos por id, clase y nombre de etiqueta, y jQuery fue un salvavidas con sus selectores inteligentes tipo css. Los navegadores se han dado cuenta desde entonces e introdujeron dos API importantes:querySelector y querySelectorAll:

// We can use document.querySelector to get the first element that matches a certain criteria.
// It's only argument is a string containing one or more CSS selectors.

var lochNess = document.querySelector(".monsters");

console.log("It's from Scotland - " + lochNess.textContent);

// We can also get all elements of a certain type or class by using document.querySelectorAll.
// This returns a NodeList of all the elements that fit our criteria.

var scary = document.querySelectorAll(".monsters");

console.log("Hide and seek champions: ");

for (var i = 0; i < scary.length; i++) {

    console.log(scary[i].innerHTML);

}
<ul>

    <li class="monsters">Nessy</li>

    <li class="monsters">Big foot</li>

    <li class="monsters">La chupacabra</li>

</ul>

3. Adjuntar y eliminar detectores de eventos

Escuchar eventos es una parte fundamental de la construcción de una aplicación web. Solía ​​haber dos campos principales que diferían en cómo se hacía esto:IE y el resto. Pero hoy solo usamos addEventListener :

var btn = document.querySelectorAll("button"),
    list = document.querySelector("ul");

// We call the addEventListener method on our desired event target(in this case a button).
// This will start a listener that will wait until a click is generated on the element.

btn[0].addEventListener("click", function () {

    // When this button is clicked we want to enable zooming of our list.

    // To do this we add an event listener to our list itself,
    // so when the cursor hovers it, the enlarge function gets called.

    list.addEventListener("mouseover", enlarge);
});

// To disable the zooming we can simply use removeEventListener.

btn[1].addEventListener("click", function () {

    // Removing event listeners doesn't work on anonymous functions, so always use a named one.

    list.removeEventListener("mouseover", enlarge);
});

// Let's create our enlarge function.

var enlarge = function () {

    // Add class zoomed to the unordered list.

    list.classList.add("zoomed");

    // When the cursor leaves the list return to normal size by removing the class.

    list.addEventListener("mouseout", function () {

        list.classList.remove("zoomed")

    });

};

// Now we want to be able to color the names by clicking them.

// When a 'click' is registered on one of the list entries it should change its color to green.
// Thanks to event delegation we can actually add an event listener to the whole parent object.
// This way we don't have to add separate event listeners to each <li>.

list.addEventListener("click", function (e) {

    // Make the coloring happen only to the clicked element by taking the target of the event.

    e.target.classList.add('green');

});
<button>Enable zoom</button>

<button>Disable zoom</button>

<br><br>

Click on any of the names to color them green

<ul>

    <li>Chewbacca</li>

    <li>Han Solo</li>

    <li>Luke</li>

    <li>Boba fett</li>

</ul>
.green {
    color: green;
}

.zoomed {
    cursor: pointer;
    font-size: 23px;
}

addEventListener solía requerir un tercer argumento (useCapture) pero ha sido opcional durante algún tiempo. Como resultado, el código se parece aún más a jQuery.

4. Manipulación de clases y atributos

Manipular los nombres de clase de un elemento sin jQuery solía ser muy inconveniente. Ya no, gracias a la propiedad classList. Y si necesita manipular atributos, tiene setAttribute.

var btn = document.querySelectorAll("button"),
    div = document.querySelector("#myDiv");

btn[0].addEventListener("click", function () {

    // Get any attribute easily.
    console.log(div.id);
});

// Element.classList stores all classes of the element in the form of a DOMTokenList.

var classes = div.classList;

btn[1].addEventListener("click", function () {

    console.log(classes);

});

btn[2].addEventListener("click", function () {

    // It supports adding and removing classes.
    classes.add("red");

});

btn[3].addEventListener("click", function () {

    // You can also toggle a class on and off
    classes.toggle("hidden");

});
<div id='myDiv' class="square"></div>

<button>Display id</button>

<button>Display classes</button>
<button>Color red</button>
<button>Toggle visibility</button>
.square {
    width: 100px;
    height: 100px;
    margin-bottom: 20px;
    border: 1px solid grey;
    border-radius: 5px;
}

.hidden {
    visibility: hidden;
}

.red {
    background-color: red;
}

5. Obtención y configuración del contenido del elemento

jQuery tiene los prácticos métodos text() y html(). En su lugar, puede usar las propiedades textContent e innerHTML, que hemos tenido durante mucho tiempo:

var myText = document.querySelector("#myParagraph"),
    btn = document.querySelectorAll("button");

// We can easily get the text content of a node and all its descendants.

var myContent = myText.textContent;

console.log("textContent:  " + myContent);

// When using textContent to alter the text of an element
// it deletes the old content and replaces it with new.

btn[0].addEventListener('click', function () {

    myText.textContent = " Koalas are the best animals ";

});

// If we want to grab all the HTML in a node (including the tags) we can use innerHTML.

var myHtml = myText.innerHTML;

console.log("innerHTML:  " + myHtml);

// To change the html simply supply new content.
// Of course we aren't limited to text only this time.

btn[1].addEventListener('click', function () {

    myText.innerHTML = "<button> Penguins are the best animals </button>";

});
<p id="myParagraph"><strong> Which are the best animals? </strong></p>

<button>Koalas</button>

<br>

<button>Penguins</button>

6. Inserción y eliminación de elementos

Aunque jQuery lo hace mucho más fácil, agregar y eliminar elementos DOM no es imposible con JavaScript simple. A continuación se explica cómo agregar, eliminar y reemplazar cualquier elemento que desee:

var lunch = document.querySelector("#lunch");

// In the HTML tab we have our lunch for today.

// Let's say we want to add fries to it.

var addFries = function () {

    // First we have to create our new element and set its content

    var fries = document.createElement("div");
    fries.innerHTML = '<li><h4> Fries </h4></li>';

    // After that's done, we can use appendChild to insert it.
    // This will make our fries appear at the end of the lunch list.

    lunch.appendChild(fries);

};

// Now we want to add cheese both before and after the beef in our burger.

var addCheese = function () {

    var beef = document.querySelector("#Beef"),

            topSlice = document.createElement("li"),
            bottomSlice = document.createElement("li");

    bottomSlice.innerHTML = topSlice.innerHTML = 'Cheese';

    // Inserting the top slice:
    // Take the parent of the beef (that's the sandwich) and use insertBefore on it.
    // The first argument to insertBefore is the new element we're gonna add.
    // The second argument is the node before which the new element is inserted.

    beef.parentNode.insertBefore(topSlice, beef);

    // The bottom slice:
    // We have to use a little trick here!
    // Supply the next nearest element as the second argument to insertBefore,
    // that way we can actually insert after the element we want.

    beef.parentNode.insertBefore(bottomSlice, beef.nextSibling);

};

var removePickles = function () {

    // Finally, we want to get rid of those pickles. Again javascript got us covered!

    var pickles = document.querySelector("#pickles");

    if (pickles) {
        pickles.parentNode.removeChild(pickles);
    }

};

// Delicious!

var btn = document.querySelectorAll("button");

btn[0].addEventListener('click', addFries);

btn[1].addEventListener('click', addCheese);

btn[2].addEventListener('click', removePickles);
<button>Add fries to lunch</button>
<button>Add cheese to sandwich</button>
<button>Remove pickles</button>

<h3>My Lunch</h3>
<ul id="lunch">
    <li><h4>My sandwich</h4></li>
    <li>Bread</li>
    <li id="pickles">Pickles</li>
    <li id="Beef">Beef</li>
    <li>Mayo</li>
    <li>Bread</li>
</ul>

7. Recorriendo el árbol DOM

Como todo verdadero ninja de JS sabe, hay mucho poder escondido en el DOM. En comparación con jQuery, las API DOM simples ofrecen una funcionalidad limitada para seleccionar ancestros o hermanos. Sin embargo, todavía hay muchas cosas que puedes hacer para cruzar el árbol.

var snakes = document.querySelector('#snakes'),
    birds = document.querySelector('#birds');

snakes.addEventListener('click', function (e) {

    // To access the parent of a certain element in the DOM tree, we use the parentNode method.

    var parent = e.target.parentNode;

    console.log("Parent: " + parent.id);

    // For the opposite, calling the .children method gets all child elements of the selected object.

    console.log("Children: ");
    var children = e.target.children;

    // This returns a HTMLCollection (a type of array), so we have to iterate to access every child's content.

    for (var i = 0; i < children.length; i++) {

        console.log(children[i].textContent);

    }
});

birds.addEventListener('click', function (e) {

    // Getting the nearest sibling to our element is self-explanatory.

    var previous = e.target.previousElementSibling;

    if (previous) {
        console.log("Previous sibling: " + previous.textContent);

    }

    var next = e.target.nextElementSibling;

    if (next) {
        console.log("Next sibling: " + next.textContent);

    }

    // However, to acquire all the siblings of a node is a bit more complex.
    // We have to take all of its parent's children and then exclude the original element.
    // This is done by using filter and calling a function that checks every child one by one.

    console.log("All siblings: ");

    Array.prototype.filter.call(e.target.parentNode.children, function (child) {
        if (child !== e.target) {
            console.log(child.textContent);
        }
    });

});
Click on the objects to see their parent and children elements
<div id="snakes">
    Snakes

    <ul id="venomous">
        Venomous
        <li>Cobra</li>
        <li>Rattlesnake</li>
    </ul>

    <ul id="non-venomous">
        Non venomous
        <li>Python</li>
        <li>Anaconda</li>
    </ul>

</div>

Click on any of the birds to see its siblings
<div>
    Birds
    <ul id="birds">
        <li>Flamingo</li>
        <li>Seagull</li>
        <li>Raven</li>
        <li>Dodo</li>
    </ul>
</div>
div {
    color: white;
    background-color: #93d0ea;
    font-family: sans-serif;
    width: 180px;
    text-align: center;
    padding: 10px;
    margin: 5px;
}

8. Recorriendo arreglos

Algunos de los métodos de utilidad que proporciona jQuery están disponibles con el estándar ES5. Para iterar arreglos, podemos usar forEach y map en lugar de sus versiones jQuery - each() y map() . Solo tenga cuidado con las diferencias en los argumentos y esto por defecto valor en las devoluciones de llamada.

var ninjaTurtles = ["Donatello", "Leonardo", "Michelangelo", "Raphael"];

// ForEach automatically iterates through an array.

ninjaTurtles.forEach(function (entry) {
    console.log(entry);
});

// The map method calls a function on every element of an array and creates a new array with the results.

var lovesPizza = ninjaTurtles.map(function (entry) {

    return entry.concat(" loves pizza!");

});

console.log(lovesPizza);

9. Animaciones

El método de animación de jQuery es superior a cualquier cosa que pueda unir usted mismo, y si necesita animaciones complejas con secuencias de comandos en su aplicación, aún debe seguir con él. Pero gracias a todas las maravillas de CSS3, algunos de los casos simples se pueden manejar con una biblioteca liviana como Animate.css, que le permite activar animaciones agregando o quitando nombres de clase a los elementos.

var btn = document.querySelectorAll("button"),
        circle = document.querySelector("#circle");

// First, we have to add a class of animated to our object, so the library can recognize it.

circle.classList.add('animated');

// We iterate over all of our buttons and add event listeners to each one.

for (var i = 0; i < btn.length; i++) {

    // Define an anonymous function here, to make it possible to use the i variable.

    (function (i) {

        btn[i].addEventListener('click', function () {

            // To start an animation you just have to add a specific class to the object.
            // In our case we stored the classes' names in the data-animation attribute of each button.

            var animation = btn[i].getAttribute('data-animation');

            circle.classList.add(animation);

            // To make it work more then once we have to remove the class after the animation is complete.

            window.setTimeout(function () {

                circle.classList.remove(animation);

            }, 1000);

        });

    }(i));

}
<button data-animation="bounce">Bounce</button>
<button data-animation="pulse">Pulse</button>
<button data-animation="fadeInLeftBig">Fade in</button>
<button data-animation="fadeOutRightBig">Fade out</button>
<button data-animation="flip">Flip</button>

<div id="circle"></div>
body {
    text-align: center;
}

#circle {
    border-radius: 50%;
    margin: 50px auto;
    width: 50px;
    height: 50px;
    background-color: #93d0ea;
}

10. AJAX

AJAX era otra tecnología que solía ser un desastre entre navegadores. La buena noticia es que ahora podemos usar el mismo código en todas partes. Sin embargo, la mala noticia es que todavía es engorroso crear instancias y enviar solicitudes AJAX con XMLHttpRequest, por lo que es mejor dejarlo en manos de una biblioteca. Pero no necesita incluir todo jQuery solo para eso. Puede utilizar una de las numerosas bibliotecas ligeras que están disponibles. Aquí hay un ejemplo de construcción de una solicitud AJAX directamente y mediante el uso de la pequeña lib reqwest:

// This simple example logs the body of our url (a html file) in the console.

// It's possible to do a manual GET request but it is somewhat a tedious task.

var request = new XMLHttpRequest();
request.open('GET', 'https://tutorialzine.com/misc/files/my_url.html', true);

request.onload = function (e) {
    if (request.readyState === 4) {

        // Check if the get was successful.

        if (request.status === 200) {
            console.log(request.responseText);
        } else {
            console.error(request.statusText);
        }
    }
};

// Catch errors:

request.onerror = function (e) {
    console.error(request.statusText);
};

request.send(null);

// Using a small library, such as Reqwest, can make your job much easier.

reqwest({
    url: 'https://tutorialzine.com/misc/files/my_url.html',
    method: 'get',
    error: function (err) {
    },
    success: function (resp) {
        console.log(resp);
    }
});

Conclusión

Esforzarse por páginas web mínimas y sin exceso de contenido es un objetivo valioso que se amortizará con tiempos de carga más rápidos y una mejor experiencia de usuario. Sin embargo, debe tener cuidado:nadie ganaría si reinventa las ruedas que jQuery le ha dado. No sacrifique las buenas prácticas de desarrollo solo para reducir la cuenta de bytes. Pero hay muchos lugares donde los consejos de hoy son perfectamente aplicables. Prueba con vainilla la próxima vez, ¡podría ser todo lo que necesitas!