10 tipů pro psaní JavaScriptu bez jQuery

jQuery je skvělá knihovna. Bylo to v době, kdy byl IE6 prohlížečem číslo jedna. Tehdy existovaly zvláštnosti a rozdíly, které bylo únavné obejít, a jQuery byl perfektní nástroj pro psaní kódu napříč prohlížeči.

Dnes však webové prohlížeče od té doby značně pokročily. Můžeme pohodlně používat všechny funkce poskytované ES5 a máme k dispozici úžasná HTML5 API, díky kterým je práce s DOM mnohem hezčí. Vývojáři jsou nyní v pozici, kdy se mohou rozhodnout vynechat jQuery pro některé projekty, a přesto si zachovat svou produktivitu.

Nechápejte mě špatně – jQuery je stále skvělá knihovna a většinou se vám bude lépe používat. Nicméně pro menší věci, jako jsou jednoduché stránky s omezenými interakcemi JS, rozšíření prohlížeče a mobilní weby, můžete použít vanilla JS. Zde je 10 tipů, které vám ve vašem snažení pomohou.

1. Poslech dokumentu Připraveno

První věc, kterou uděláte při psaní jQuery, je zabalení kódu do $(document).ready() zavolejte, abyste věděli, kdy je DOM připraven k manipulaci. Bez jQuery máme událost DOMContentLoaded. Zde je návod, jak se používá:

// 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. Výběr prvků

Kdysi jsme mohli prvky vybírat pouze podle id, třídy a názvu tagu a jQuery byl záchranou života se svými chytrými selektory podobnými css. Prohlížeče se od té doby chytly a představily dvě důležitá rozhraní API - querySelector a 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. Připojování a odebírání posluchačů událostí

Poslouchání událostí je základní součástí budování webové aplikace. Dříve existovaly dva hlavní tábory, které se lišily v tom, jak se to dělalo - IE a zbytek. Ale dnes používáme pouze 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 používá se k vyžadování třetího argumentu (useCapture), ale ten byl nějakou dobu volitelný. Výsledkem je, že kód vypadá ještě více jako jQuery.

4. Manipulace s třídami a atributy

Manipulace s názvy tříd prvku bez jQuery bývala velmi nepohodlná. Už ne, díky vlastnosti classList. A pokud potřebujete manipulovat s atributy, máte 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. Získání a nastavení obsahu prvku

jQuery má praktické metody text() a html(). Místo nich můžete použít vlastnosti textContent a innerHTML, které máme již velmi dlouho:

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. Vkládání a odebírání prvků

Ačkoli to jQuery značně usnadňuje, přidávání a odstraňování prvků DOM není nemožné s prostým JavaScriptem. Zde je návod, jak přidat, odebrat a nahradit libovolný prvek:

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. Procházka stromem DOM

Jak každý správný JS ninja ví, v DOM se skrývá spousta síly. Ve srovnání s jQuery nabízejí jednoduchá DOM API omezenou funkčnost pro výběr předků nebo sourozenců. Stále však existuje spousta věcí, které můžete udělat, abyste mohli cestovat napříč stromem.

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. Smyčka přes pole

Některé z obslužných metod, které poskytuje jQuery, jsou dostupné se standardem ES5. Pro iteraci polí můžeme místo jejich verzí jQuery použít forEach a map - each() a map() . Dejte si pozor na rozdíly v argumentech a výchozí toto hodnotu ve zpětných voláních.

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. Animace

Animovaná metoda jQuery je lepší než cokoli, co byste mohli slepit sami, a pokud ve své aplikaci potřebujete složité skriptovatelné animace, měli byste se jí držet. Ale díky všem zázrakům CSS3 lze některé jednoduché případy zvládnout pomocí odlehčené knihovny, jako je Animate.css, která vám umožňuje spouštět animace přidáním nebo odebráním názvů tříd k prvkům.

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 byla další technologie, která bývala nepořádkem napříč prohlížeči. Dobrou zprávou je, že nyní můžeme všude používat stejný kód. Špatnou zprávou však je, že vytváření instancí a odesílání požadavků AJAX pomocí XMLHttpRequest je stále těžkopádné, takže je nejlepší to nechat na knihovně. K tomu ale nemusíte zahrnout celý jQuery. Můžete použít jednu z mnoha dostupných odlehčených knihoven. Zde je příklad vytvoření požadavku AJAX přímo a pomocí malé reqwest lib:

// 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);
    }
});

Závěr

Snaha o minimální webové stránky s nulovým nadýmáním je důstojným cílem, který se vyplatí rychlejším načítáním a lepší uživatelskou zkušeností. Měli byste však být opatrní – nikdo by nevyhrál, pokud byste znovu objevili kola, která vám jQuery dal. Neobětujte dobré vývojové postupy jen proto, abyste snížili odpočítávání bajtů. Ale je spousta míst, kde se dnešní tipy skvěle hodí. Zkuste jít příště na vanilku, možná to bude vše, co potřebujete!