Как обойтись без jQuery

jQuery - огромная библиотека. Она пришла приблизительно в то время, когда IE6 был браузером номер один. Тогда было много специфических моментов и разногласий, что делали процесс разработки утомительным, и jQuery был идеальным инструментом для написания кроссбраузерного кода.

С тех пор, однако, веб-браузеры намного усовершенствовались. Вы можете с удобством использовать все возможности, предоставляемые ES5 и имеете в полном распоряжении огромную API-библиотеку HTML5, которая делает работу с DOM-элементами намного приятнее. Разработчики теперь могут выбирать, что же можно оставлять из jQuery для некоторых проектов, продолжая сохранять свою производительность.

Не поймите неправильно – jQuery по-прежнему отличная библиотека, и чем чаще вы будете использовать ее, тем лучше. Тем не менее, для небольших проектов, например, простые страницы с ограниченным JS взаимодействием, расширениями браузеров и мобильных сайтов, вы можете использовать vanlla JS.

Вот 10 советов, которые помогут в вашей деятельности.

1. Обработка события готовности документа (Document Ready)

Первое, что вы делаете, когда пишете на jQuery, это упаковка своего кода в вызов $(document).ready(), для того, чтобы определить готовность DOM к манипуляциям. Без jQuery у вас есть событие DOMContentLoaded. Вот как оно используется:

document.addEventListener('DOMContentLoaded', function () {
    console.log('Aloha');
});

2. Выбор элементов

Давным-давно Вы могли только выбирать элементы по id, классу и имени тега, а jQuery с ее умными CSS-селекторами выступала своеобразным спасателем. Браузеры исправили это и представили две важные API - querySelector и querySelectorAll.

<ul>
    <li class="monsters">Nessy</li>
    <li class="monsters">Big foot</li>
    <li class="monsters">La chupacabra</li>
</ul>
<script>
    // Мы можем использовать document.querySelector, чтобы получить первый элемент, который соответствует определенным критериям.
    // Это единственный аргумент является строкой, содержащей один или более CSS селекторы.
    var lochNess = document.querySelector(".monsters");
    console.log("It's from Scotland - " + lochNess.textContent);

    // Мы также можем получить все элементы определенного типа или класса, используя document.querySelectorAll.
    // Это возвращает NodeList всех элементов, которые соответствуют нашим критериям.
    var scary = document.querySelectorAll(".monsters");
    console.log("Hide and seek champions: ");

    for (var i = 0; i < scary.length; i++) {
        console.log(scary[i].innerHTML);
    }
</script>

Примеры селекторов для querySelector и querySelectorAll

jQuery - селекторcss - селекторОписание
:eq(0):nth-of-type(1)получить первый этого типа, эквавалент jQuery

Здесь – Сводная таблица селекторов CSS.

3. Установка и удаление слушателей событий

Прослушивание событий - фундаментальная часть построения веб-приложения. Принято было использовать две основные стороны, которые отличались тем, каким способом все было сделано - IE и остальное. Но сегодня мы просто используем addEventListener.

<style>
    .green {
        color: green;
    }
    .zoomed {
        cursor: pointer;
        font-size: 23px;
    }
</style>
<button>Разрешить zoom</button>
<button>Запретить zoom</button>
<br> <br>
Нажмите на любое имя, для изменения его цвета на зеленый:
<ul>
    <li>Вася</li>
    <li>Петя</li>
    <li>Сережа</li>
    <li>Костя</li>
</ul>
<script>
    var btn = document.querySelectorAll("button"),
        list = document.querySelector("ul");

    // Мы вызываем метод addEventListener на нашем цели событий (в данном случае кнопка).
    // Это будет начать слушателя, что будет ждать до щелчка генерируется на элементе.
    btn[0].addEventListener("click", function () {
        // Когда эта кнопка нажата, мы хотим включить масштабирование нашего списка.
        // Для этого мы добавляем обработчик событий на наш список,
        // Так при наведении курсора на него будет вызыватся функция enlarge
        list.addEventListener("mouseover", enlarge);
    });

    // Чтобы отключить масштабирование, мы можем просто использовать removeEventListener.
    btn[1].addEventListener("click", function () {
        // Удаление обработчиков событий не работает на анонимные функции, поэтому всегда используйте именнованные.
        list.removeEventListener("mouseover", enlarge);
    });
    // Создадим нашу функцию увеличения.
    var enlarge = function () {

        // Добавить класс zoomed в список.
        list.classList.add("zoomed");

        // Если курсор покидает список вернуться к нормальному размеру, удаляя класс.
        list.addEventListener("mouseout", function () {
            list.classList.remove("zoomed")
        });
    };
    // Теперь мы хотим иметь возможность раскрасить имена, выбрав их.
    // Когда "нажмите кнопку" зарегистрирован на одной из записей в списке следует изменить свой цвет на зеленый.
    // Благодаря делегации событий мы можем на самом деле добавить прослушиватель событий в родительский объект всей.
    // Таким образом, мы не должны добавить отдельные обработчики событий каждого <LI>.
    list.addEventListener("click", function (e) {
    // Изменить цвет эллемента, если на него щелкнули.
    e.target.classList.add('green');
    });
</script>

4. Манипулирование классами и свойствами

Манипулирование именами классов элементов без jQuery было очень неудобно использовать. Но проблема была решена благодаря свойству ClassList. И если нужно управление атрибутами, то используйте SetAttribute.

<style>
    .square {
        width: 100px;
        height: 100px;
        margin-bottom: 20px;
        border: 1px solid grey;
        border-radius: 5px;
    }
    .hidden {
        visibility: hidden;
        /*display: none;*/
    }
    .red {
        background-color: red;
    }
</style>
<div id='myDiv' class="square"></div>
<button>Display id</button>
<button>Display classes</button>
<button>Color red</button>
<button>Toggle visibility</button>
<script>
    var btn = document.querySelectorAll("button"),
        div = document.querySelector("#myDiv");

    btn[0].addEventListener("click", function () {
        // Получить любой атрибут легко.
        console.log(div.id);
    });
    // Element.classList хранит все классы элемента в виде DOMTokenList.
    var classes = div.classList;
    btn[1].addEventListener("click", function () {
        console.log(classes);
    });
    btn[2].addEventListener("click", function () {
        // Он поддерживает добавление и удаление классов.
        classes.add("red");
    });
    btn[3].addEventListener("click", function () {
        // Вы также можете переключаться класс и выключать
        classes.toggle("hidden");
    });
</script>

5. Получение и установка содержимого элементов

jQuery имеет удобный текст и html( ) методы. Вместо их можно использовать свойства textContent и innerHTML, которые были у нас в течение очень долгого времени.

<p id="myParagraph"><strong> Which are the best animals? </strong></p>
<button>Koalas</button>
<br>
<button>Penguins</button>
<script>
    var myText = document.querySelector("#myParagraph"),
        btn = document.querySelectorAll("button");

    // Мы можем легко получить текстовое содержимое узла и всех его потомков.
    var myContent = myText.textContent;
    console.log("textContent:  " + myContent);

    // При использовании TextContent изменить текст элемента
    // Удаляет старую содержание и заменяет его новым.
    btn[0].addEventListener('click', function () {
        myText.textContent = " Koalas are the best animals ";
    });

    // Если мы хотим, чтобы захватить все HTML в узле (включая теги), мы можем использовать innerHTML.
    var myHtml = myText.innerHTML;
    console.log("innerHTML:  " + myHtml);

    // Чтобы изменить HTML просто поставить новое содержание.
    // Конечно, мы не ограничены в текст только на этот раз.
    btn[1].addEventListener('click', function () {
        myText.innerHTML = "<button> Penguins are the best animals </button>";
    });
</script>

6. Установка и удаление элементов

Хотя jQuery и делает все намного проще, добавление и удаление DOM-элементов невозможно без простого JavaScript. Здесь показано, как добавлять, удалять и заменять любые элементы, какие Вы только захотите.

<button>Add fries to lunch</button>
<button>Add cheese to sandwich</button>
<button>Remove pickles</button>

<h2>My Lunch</h2>
<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>

<script>
    var lunch = document.querySelector("#lunch");

    // На вкладке HTML мы имеем наш обед на сегодняшний день.
    // Скажем, мы хотим, чтобы добавить к нему картофель.
    var addFries = function () {


        // Сначала мы должны создать наш новый элемент и его содержание
        var fries = document.createElement("div");
        fries.innerHTML = '<li><h4> Fries </h4></li>';

        // После этого делается, мы можем использовать AppendChild, чтобы вставить его.
        // Это позволит сделать наши фри появляются в конце списка на обед.
        lunch.appendChild(fries);

    };

    // Теперь мы хотим, чтобы добавить сыр и до, и после говядины в нашей гамбургер.
    var addCheese = function () {

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

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

        // Установка верхняя часть:
        // Возьмите родителя говядины (это сэндвич) и использовать InsertBefore на нем.
        // Первый аргумент InsertBefore является новым элементом мы собираемся добавить.
        // Второй аргумент узел, перед которым новый элемент вставляется.
        beef.parentNode.insertBefore(topSlice, beef);

        // Нижняя часть:
        // Мы должны использовать маленькую хитрость здесь!
        // Поставка на следующий ближайший элемент в качестве второго аргумента InsertBefore,
        // Таким образом, мы можем на самом деле вставить после элемента мы хотим.
        beef.parentNode.insertBefore(bottomSlice, beef.nextSibling);
    };

    var removePickles = function () {

        // Наконец, мы хотим, чтобы избавиться от этих pickles.
        var pickles = document.querySelector("#pickles");
        if (pickles) {
            pickles.parentNode.removeChild(pickles);
        }
    };

    // Вкусно!
    var btn = document.querySelectorAll("button");
    btn[0].addEventListener('click', addFries);
    btn[1].addEventListener('click', addCheese);
    btn[2].addEventListener('click', removePickles);
</script>

7. Прохождение по DOM дереву

Любой настоящий JS-ниндзя знает, что есть много возможностей, скрытых в DOM. По сравнению с jQuery простые интерфейсы DOM предлагают ограниченную функциональность для выбора нескольких уровней. И тем не менее, есть множество вещей, которые Вы можете делать, путешествуя по DOM - дереву.

<style>
    div {
        color: white;
        background-color: #93d0ea;
        font-family: sans-serif;
        width: 180px;
        text-align: center;
        padding: 10px;
        margin: 5px;
    }
</style>

<p>Нажмите на объекты, чтобы увидеть их родительские и дочерние элементы.</p>
<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>

<p>Нажмите на любую из птиц, чтобы увидеть её братьев и сестер.</p>
<div>
    Birds
    <ul id="birds">
        <li>Flamingo</li>
        <li>Seagull</li>
        <li>Raven</li>
        <li>Dodo</li>
    </ul>
</div>

<script>
    var snakes = document.querySelector('#snakes'),
        birds = document.querySelector('#birds');
    snakes.addEventListener('click', function (e) {
        // Чтобы получить доступ к родителю определенного элемента в DOM дереве, мы используем метод ParentNode.
        var parent = e.target.parentNode;
        console.log("Parent: " + parent.id);

        // Для напротив, назвав .children метод получает все дочерние элементы выбранного объекта.
        console.log("Children: ");
        var children = e.target.children;

        // Это возвращает HTMLCollection (тип массив), так что мы должны повторять для доступа к контенту каждого ребенка.
        for (var i = 0; i < children.length; i++) {
            console.log(children[i].textContent);
        }
    });
    birds.addEventListener('click', function (e) {
        // Получить ближайший узел к нашему элементу.
        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);
        }

        // Чтобы получить всех братьев и сестер узла нужно немного больше.
        // Мы должны принять всех детей родителя, а затем исключить оригинальный элемент.
        // Это делается с помощью фильтра и вызова функции, которая проверяет каждому ребенку по одному.
        console.log("All siblings: ");

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

    });
</script>

8. Обработка массивов

Некоторые из утилитных методов, которые предоставляет jQuery, доступны со стандартом ES5. При переборе массивов можно использовать forEach и map вместо их jQuery-аналогов - each() и map(). Просто будьте осторожны при различиях в аргументах и значениях по умолчанию в обратных вызовах.

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

// ForEach автоматически перебирает массив.
ninjaTurtles.forEach(function (entry) {
console.log(entry);
});

// Метод map вызывает функцию на каждом элементе массива и создает новый массив с результатами.
var lovesPizza = ninjaTurtles.map(function (entry) {
    return entry.concat(" loves pizza!");
});

console.log(lovesPizza);
</script>

9. Animations

Методы анимации jQuery самым лучшим образом подходят ко всему, что Вы бы хотели «оживить». Если нужны сложные анимации из скриптов в приложении, Вы должны по-прежнему иметь дело с ней. Но благодаря всем чудесам CSS3, некоторые простые случаи можно обработать с помощью легкой библиотеки Animate.css, которая позволяет запускать анимацию, добавляя или удаляя имена классов элементов.

<style>
    body {
        text-align: center;
    }
    #circle {
        border-radius: 50%;
        margin: 50px auto;
        width: 50px;
        height: 50px;
        background-color: #93d0ea;
    }
</style>

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

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

    // Во-первых, мы должны добавить класс анимированные нашего объекта, поэтому библиотека может признать его.
    circle.classList.add('animated');

    // Мы перебора всех наших кнопок и добавить слушателей событий к каждому.
    for (var i = 0; i < btn.length; i++) {
        // Определить анонимную функцию здесь, чтобы сделать его можно использовать переменную я.
        (function (i) {
            btn[i].addEventListener('click', function () {
                // Для начала анимации вы просто должны добавить определенный класс к объекту.
                // В нашем случае мы сохранили имена классов »в данных анимации атрибута каждой кнопки.
                var animation = btn[i].getAttribute('data-animation');
                circle.classList.add(animation);

                // Для того, чтобы его работу более одного раза, мы должны удалить класс после завершения анимации.
                window.setTimeout(function () {
                    circle.classList.remove(animation);
                }, 1000);
            });
        }(i));
    }
</script>

10. Ajax

Ajax – это еще одна технология, которая используется при кроссбраузерном беспорядке. Теперь можно использовать один и тот же код везде.

<script>
// Это простой пример регистрирует тело нашего URL (а) файл HTML в консоли.
// Это можно делать вручную запрос GET, но это несколько утомительно.
var request = new XMLHttpRequest();
request.open('GET', 'http://htmlweb.ru/html/', true);

request.onload = function (e) {
    if (request.readyState === 4) {
        // Проверка, запрос был успешным.
         if (request.status === 200) {
            console.log(request.responseText);
        } else {
            console.error(request.statusText);
        }
    }
};

// Обратка ошибок:
request.onerror = function (e) {
console.error(request.statusText);
};

request.send(null);
</script>

Выводы

Стремление к минимальному, нулевому количеству наворотов на веб-странице - достойная цель, что окупит себя быстрой загрузкой и лучшим пользовательским опытом. Но будьте осторожны - никто не выиграет, если Вы будете изобретать велосипед, который уже используется в jQuery. Не жертвуйте хорошей практикой разработки только для того, чтобы сократить количество кода. Но есть множество мест, где на сегодня советы вполне применимы. Например, на данном сайте библиотека jQuery не используется.

Замена большинства функций jQuery - $

<script>
$ = function (d, e, c, f, g) {
    c = function (a, b) {
        return new f(a, b)
    };
    f = function (a, b) {
        e.push.apply(this, a ? a.nodeType || a == window ? [a] :
            "" + a === a ? /</.test(a) ? ((g = d.createElement(b || "q")).innerHTML = a, g.children) :
                (b && c(b)[0] || d).querySelectorAll(a) : /f/.test(typeof a) ? /c/.test(d.readyState) ? a() :
                d.addEventListener("DOMContentLoaded", a) : a : e)
    };
    c.fn = f.prototype = e;
    c.fn.addClass = function (className) {
        this.forEach(function (item) {
            var classList = item.classList;
            classList.add.apply(classList, className.split(/\s/));
        });
        return this;
    };
    c.fn.removeClass = function (className) {
        this.forEach(function (item) {
            var classList = item.classList;
            classList.remove.apply(classList, className.split(/\s/));
        });
        return this;
    };
    c.fn.show = function (className) {
        this.forEach(function (item) {
            var classList = item.style.display = 'block';
        });
        return this;
    };
    c.fn.hide = function (className) {
        this.forEach(function (item) {
            var classList = item.style.display = 'none';
        });
        return this;
    };
    return c
}(document, []);
</script>

Подсмотрено здесь: https://habrahabr.ru/post/273751/, https://github.com/finom/balalaika.

Сводная таблица jQuery - эквивалентов на чистом js

jQueryЧистый JavaScript
$('.el').prev();
$('.el').next();
document.querySelector('.el').previousElementSibling;
document.querySelector('.el').nextElementSibling;
var els = $('.el');var els = document.querySelectorAll('.el');
var newEl = $('>div/<');var newEl = document.createElement('div');
$('.el').on('event', function() { });[].forEach.call(document.querySelectorAll('.el'), function (el) { el.addEventListener('event', function() { }, false); });
$('.el’).html();document.querySelector('.el’).innerHTML;
$('.el').filter(':first').attr('key', 'value');
$('.el').filter(':first').attr('key');
document.querySelector('.el').setAttribute('key', 'value');
document.querySelector('.el').getAttribute('key');
$(‘.el’).offset();document.querySelector('.el').getBoundingClientRect();
$('.el').addClass('class');
$('.el').removeClass('class');
$('.el').toggleClass('class');
document.querySelector('.el').classList.add('class');
document.querySelector('.el').classList.remove('class');
document.querySelector('.el').classList.toggle('class');
$('.el').append($('<div/>'));document.querySelector('.el').appendChild(document.createElement('div'));
var clonedEl = $('.el').clone();var clonedEl = document.querySelector('.el').cloneNode(true);
$('.el').remove();remove('.el');
function remove(el) {
var toRemove = document.querySelector(el);
toRemove.parentNode.removeChild(toRemove);
}
$("#container").empty();document.getElementById("container").innerHTML = null;
// или
var c = document.getElementById("container");
while (c.lastChild) c.removeChild(c.lastChild);
$('.el').parent();document.querySelector('.el').parentNode;
$.get('url', function (data) { ... });
$.post('url', {data: data}, function (data) { ... });
// get
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function (data) { ... }
xhr.send();

// post
var xhr = new XMLHttpRequest()
xhr.open('POST', url);
xhr.onreadystatechange = function (data) { ... }
xhr.send({data: data});

jQuery - Описание библиотеки


.