В последние годы jQuery стал де-факто библиотекой JavaScript в Интернете. Он устраняет многие несоответствия между браузерами и добавляет желаемый слой синтаксического сахара в сценарии на стороне клиента. Одной из основных проблем, которую он отвлекает, является манипулирование DOM, но с момента его создания собственные API-интерфейсы для браузеров значительно улучшились, и идея о том, что вам может не понадобиться jQuery , стала набирать популярность.
Вот несколько причин, почему:
- JQuery включает в себя множество функций, которые вам не нужны или не используются (поэтому вес не требуется).
- JQuery это слишком много вещей, чтобы слишком много людей. Часто небольшие библиотеки могут лучше выполнять определенные задачи.
- С точки зрения манипулирования DOM, браузерные API теперь могут делать большую часть того, что может делать jQuery.
- API браузеров теперь более синхронизированы, например, используя
addEventListener
вместоattatchEvent
.
Так в чем проблема?
Проблема в том, что манипулирование DOM с использованием ванильного (или простого) JavaScript может быть проблемой по сравнению с jQuery. Это потому, что вам нужно читать и писать более избыточный код и иметь дело с бесполезным NodeList браузера .
Сначала давайте посмотрим, что такое NodeList
в соответствии с MDN:
Объекты NodeList являются коллекциями узлов, таких как возвращаемые Node.childNodes и методом document.querySelectorAll.
И иногда есть живые списки NodeLists (что может сбить с толку):
В некоторых случаях NodeList является живой коллекцией, что означает, что изменения в DOM отражаются в коллекции. Например, Node.childNodes является живым.
Это может быть проблемой, потому что вы не можете сказать, какие из них являются живыми, а какие статичными. Если вы не удалите каждый из узлов из NodeList
а затем убедитесь, что NodeList
пуст. Если он пуст, значит, у вас есть живой NodeList
(что просто плохая идея).
Также браузер не предоставляет никаких полезных методов для манипулирования этими объектами NodeList
.
Например, к сожалению, невозможно forEach
узлы с помощью forEach
:
var nodes = document.querySelectorAll('div'); nodes.forEach(function(node) { // do something }); // Error: nodes.forEach is not a function
Итак, вы должны сделать:
var nodes = document.querySelectorAll('div'); for(var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; // do something }
Или даже остались с использованием «взломать»:
[].forEach.call(document.querySelectorAll('div'), function(node) { // do something });
Родной NodeList
браузера NodeList
только один метод: item . Это возвращает узел из NodeList
по индексу. Это совершенно бесполезно, когда мы можем получить доступ к этому узлу, как если бы мы использовали массив (используя array[index]
):
var nodes = document.querySelectorAll('div'); nodes.item(0) === nodes[0]; // true
Вот тут- то и появляется NodeList.js — чтобы упростить манипулирование DOM с помощью нативных API браузера, как и с jQuery, но с минимальными 4k.
Решение
Я создал NodeList.js, потому что я всегда использовал нативные API-интерфейсы DOM, но хотел сделать их более краткими, чтобы убрать большую часть избыточности при написании моего кода (например, for
циклов).
NodeList.js — это оболочка для нативных API DOM, которая позволяет вам манипулировать массивом узлов (AKA my NodeList
), как если бы это был один узел. Это дает вам гораздо больше функциональности, чем родные объекты браузера NodeList
.
Если это звучит хорошо для вас, возьмите копию NodeList.js из официального репозитория GitHub и следуйте инструкциям этого руководства.
Использование:
Выбор узлов DOM прост:
$$(selector); // returns my NodeList
Этот метод использует querySelectorAll(selector)
под капотом.
Но как это сочетается с JQuery?
Рад, что ты спросил. Давайте поместим ванильный JS, jQuery и NodeList.js один на один.
Допустим, у нас есть три кнопки:
<button></button> <button></button> <button></button>
Давайте изменим текст каждой кнопки на «Click Me» :
Ваниль JS:
var buttons = document.querySelectorAll('button'); // returns browser's useless NodeList for(var i = 0, l = buttons.length; i < l; i++) { buttons[i].textContent = 'Click Me'; }
JQuery:
$('button').text('Click Me');
NodeList.js:
$$('button').textContent = 'Click Me';
Здесь мы видим, что NodeList.js может эффективно обрабатывать NodeList
как один узел. То есть у нас есть ссылка на NodeList
и мы просто устанавливаем его свойство textContent
«Click Me» . Затем NodeList.js сделает это для каждого узла в NodeList
. Аккуратно, а?
Если бы мы хотели цепочку методов (а-ля jQuery), мы бы сделали следующее, что возвращает ссылку на NodeList
:
$$('button').set('textContent', 'Click Me');
Теперь давайте добавим слушатель события click
для каждой кнопки:
Ваниль JS:
var buttons = document.querySelectorAll('button'); // returns browser's useless NodeList for(var i = 0, l = buttons.length; i < l; i++) { buttons[i].addEventListener('click', function() { this.classList.add('clicked'); }); }
JQuery:
$('button').on('click', function() { $(this).addClass('click'); // or mix jQuery with native using `classList`: this.classList.add('clicked'); });
NodeList.js:
$$('button').addEventListener('click', function() { this.classList.add('clicked'); });
Итак, метод jQuery on
довольно хорош. Моя библиотека использует Native DOM API браузера (следовательно, addEventListener
), но это не мешает нам создавать псевдоним для метода:
$$.NL.on = $$.NL.addEventListener; $$('button').on('click', function() { this.classList.add('clicked'); });
Ницца! И это демонстрирует, как именно мы добавили бы наши собственные методы:
$$.NL.myNewMethod = function() { // loop through each node with a for loop or use forEach: this.forEach(function(element, index, nodeList) {...} // where `this` is the NodeList being manipulated }
NodeList.js о методах массива
NodeList.js наследуется от Array.prototype , но не напрямую, так как некоторые методы изменены, поэтому имеет смысл использовать их с NodeList
(массивом узлов).
Push и Unshift
Например: методы push и unshift могут принимать узлы только в качестве аргументов, иначе они выдадут ошибку:
var nodes = $$('body'); nodes.push(document.documentElement); nodes.push(1); // Uncaught Error: Passed arguments must be a Node
Таким образом, push
и unshift
возвращают NodeList
чтобы разрешить цепочку методов, то есть это не то же самое, что Array#unshift
методы JavaScript Array#push
или Array#unshift
, которые принимают все и возвращают новую длину Array
. Если нам нужна длина NodeList
мы просто используем свойство length
.
Оба эти метода, так же как и встроенные в JavaScript методы Array
, изменяют NodeList
.
Concat
Метод concat будет принимать следующие аргументы:
-
Node
-
NodeList
(как родной браузер, так и версия NodeList.js) -
HTMLCollection
-
Array of Nodes
-
Array of NodeList
-
Array of HTMLCollection
concat
— рекурсивный метод , поэтому эти массивы могут быть настолько глубокими, насколько нам нравится, и будут сглажены. Однако если какой-либо из элементов в переданных массивах не имеет Node
, NodeList
или HTMLCollection
он выдаст Error
.
concat
возвращает новый NodeList
точно так же, как и метод javascript Array#concat
.
Pop, Shift, Map, Slice, Filter
Методы pop и shift могут принимать необязательный аргумент относительно количества узлов, которые нужно NodeList
или shift
из NodeList
. В отличие от встроенного в JavaScript Array#pop
или Array#shift
котором всегда появляется или shift
один элемент из массива независимо от того, что передается в качестве аргумента.
Метод map возвращает NodeList
если каждое сопоставленное значение является Node
, или массив сопоставленных значений, если нет.
Методы слайса и фильтра действуют так же, как и в реальных массивах, но возвращают NodeList
.
Поскольку NodeList.js не наследуется напрямую от Array.prototype
если метод добавляется в Array.prototype
после загрузки NodeList.js, он не будет наследоваться.
Вы можете проверить остальные методы массива NodeList.js здесь .
Специальные методы
Существует четыре метода, уникальных для NodeList.js, а также свойство под названием owner
, которое является эквивалентом свойства prevObject
в jQuery.
Методы get
и set
:
Есть некоторые элементы со свойствами, уникальными для этого вида элементов (например, свойство href
в теге привязки). Вот почему $$('a').href
вернет undefined
— это свойство, которое наследует не каждый элемент в NodeList
. Вот как мы будем использовать метод get для доступа к этим свойствам:
$$('a').get('href'); // returns array of href values
Метод set можно использовать для установки этих свойств для каждого элемента:
$$('a').set('href', 'https://sitepoint.com/');
set
также возвращает NodeList
чтобы разрешить цепочку методов. Мы можем использовать это для таких вещей, как textContent
(оба эквивалентны):
$$('button').textContent = 'Click Me'; $$('button').set('textContent', 'Click Me'); // returns NodeList so you can method chain
Мы также можем установить несколько свойств за один вызов:
$$('button').set({ textContent: 'Click Me', onclick: function() {...} });
И все вышеперечисленное может быть сделано с произвольными свойствами, такими как style
:
$$('button').style; // this returns an `Array` of `CSSStyleDeclaration` $$('button').style.set('color', 'white'); $$('button').style.set({ color: 'white', background: 'lightblue' });
Метод call
Метод call позволяет вам вызывать эти методы, уникальные для элемента (например, pause
для элемента video):
$$('video').call('pause'); // returns NodeList back to allow Method Chaining
Метод item
Метод item является эквивалентом метода eQ в jQuery . Он возвращает NodeList
содержащий только узел переданного индекса:
$$('button').item(1); // returns NodeList containing the single Node at index 1
owner
недвижимости
Свойство владельца является эквивалентом prevObject
jQuery.
var btns = $$('button'); btns.style.owner === btns; // true
btns.style
возвращает массив стилей, а owner
возвращает вам NodeList
которого был отображен style
.
NodeList.js Совместимость
Моя библиотека совместима со всеми основными новыми браузерами, как описано ниже.
браузер | Версия |
---|---|
Fire Fox | 6+ |
Сафари | 5.0.5+ |
Хром | 6+ |
IE | 9+ |
опера | 11.6+ |
Вывод
Теперь мы наконец можем работать с полезным объектом NodeList
!
Приблизительно за 4k вы получаете все функции, упомянутые выше, и еще много, о чем вы можете узнать в репозитории GitHub NodeList.js .
Поскольку NodeList.js использует браузер в качестве зависимости, никаких обновлений делать не нужно. Всякий раз, когда браузеры добавляют новые методы / свойства к элементам DOM, вы автоматически сможете использовать эти методы / свойства через NodeList.js. Все это означает, что единственное, о чем вам нужно беспокоиться, — это методы, от которых избавляются браузеры. Обычно они используются очень редко, потому что мы не можем сломать сеть.
Так что ты думаешь? Это библиотека, которую вы хотели бы использовать? Какие-то важные функции отсутствуют? Я хотел бы услышать от вас в комментариях ниже.