В jQuery мы имеем функцию, подобную этой
$('button').each(function(i) {
$('button').eq(i).css('background', 'red');
});
Как мы можем заменить этот код на обычный JavaScript?
В jQuery мы имеем функцию, подобную этой
$('button').each(function(i) {
$('button').eq(i).css('background', 'red');
});
Как мы можем заменить этот код на обычный JavaScript?
Выбор DOM с помощью querySelectorAll()
Браузеры имеют несколько способов выбора элементов из DOM, но, возможно, наиболее гибким и удобным является querySelectorAll
. Он позволяет использовать селектор стиля CSS для захвата всех соответствующих элементов из заданного корня.
В вашем случае это будет выглядеть так:
document.querySelectorAll("button");
Сокращение querySelectorAll()
Как ни крути, это немного многословно, поэтому нередко создавать функцию обертывания, которая сокращает ее. Это то, что мы сделаем здесь, указав ему имя Q
.
function Q(root, selector) {
if (typeof root === "string") {
selector = root
root = document
}
return root.querySelectorAll(selector)
}
Первый аргумент - это контекст, из которого вы делаете выделение, а второй - селектор. Если вы передаете только строку, она будет использовать document
в качестве контекста.
Итак, теперь ваш выбор DOM будет таким, который мы будем использовать в дальнейшем:
Q("button");
Заимствование Array.prototype.forEach
Довольно простой способ создания функциональной циклической конструкции - заимствовать forEach
метод Array.prototype
и вызвать его на сбор элементов с помощью функции .call()
метод следующим образом:
Array.prototype.forEach.call(Q("buttons"), function(el) {
el.style.background = "red";
});
Или в самых современных браузерах мы можем использовать функции стрелок, чтобы немного сократить его:
Array.prototype.forEach.call(Q("buttons"), el => el.style.background = "red");
Связывание и кэширование заимствованного .forEach()
Задолженность .forEach()
может быть сокращена, если в начале вашего приложения вы используете прототип функции bind()
для привязки .forEach()
к значению this
.call()
.
const each = Function.call.bind(Array.prototype.forEach);
Таким образом вы можете просто называть его как функцию, которая получает коллекцию элементов в качестве первого аргумента.
each(Q("button"), function(el) {
el.style.background = "red";
});
Или снова используя функцию стрелки в некоторых из новейших браузеров:
each(Q("button"), el => el.style.background = "red");
Использование Array.from()
Был также введен метод Array.from
, чтобы легко преобразовывать объекты, подобные массиву, в реальные массивы. Это позволит вам напрямую использовать .forEach()
и может быть исправлена в устаревшие браузеры с помощью простого polyfill (см. Ссылку docs).
Array.from(Q("button")).forEach(function(el) {
el.style.background = "red";
});
Если вы поместите вызов Array.from
непосредственно в нашу функцию Q
сверху, вы сможете напрямую вызвать .forEach()
.
Q("button").forEach(function(el) {
el.style.background = "red";
});
Использование цикла for-of
В последних браузерах вы можете использовать for-of
loop, делая все очень короткое и чистое:
for (const el of Q("button")) {
el.style.background = "red";
}
Таким образом, нет необходимости конвертировать в Array
или использовать .forEach
.
Трансляция современного кода
В приведенных выше примерах, которые требуют самых современных браузеров, доступны транспилеры (например Babel), которые будут переводить последние стандартов в код, который будет работать в старых браузерах.
Создание пользовательского each()
В качестве побочного примечания, если вы хотите, чтобы this
ссылался на текущий элемент или имел какое-либо другое конкретное поведение, вот базовая реализация each
, которая получает коллекцию и обратный вызов.
function each(a, callback) {
for (var i = 0; i < a.length; i++) {
callback.call(a[i], a[i], i, a);
}
}
Хотя использование this
таким образом вообще не требуется, поскольку у вас уже есть элемент как параметр.
Вы можете использовать функцию getElementsByTagName()
, которая запрашивает DOM для элементов определенного тега и возвращает коллекцию элементов. Вы можете вызвать эту функцию на document
, или вы можете быть более конкретным и выбрать элемент с помощью document.getElementById()
, а затем искать теги внутри этого элемента.
В любом случае, когда у вас есть коллекция элементов, вы можете затем перебирать коллекцию и применять соответствующие стили.
//query the document for all <button> elements
var buttons = document.getElementsByTagName('button');
/* -- OR -- */
//query the document for all buttons inside of a specific element
var container = document.getElementById('container');
var buttons = container.getElementsByTagName('button');
//loop over the collection of buttons and set each background to 'red'
for(var i=0; i<buttons.length; i++) {
buttons[i].style.background = "red";
}
Edit: Я понимаю, что JS не поддерживает JQuery для каждой функции. OP не заявлял, что хотел бы видеть это конкретно, просто способ реализовать функциональность $.each()
с помощью JS (так как есть много возможностей). Этот пример - просто тривиальный подход, использующий очень базовую концепцию.
var buttons = document.querySelectorAll("button");
for(var x in buttons){
var e = buttons[x];
e.innerHTML="stuff";
}
как указывал косоглазие, должны быть кнопки [x] и var x. извините за это.
Поддерживается больше браузеров, так как он не использует forEach
.
Если вы используете getElementsByTagName
, добавьте функцию в HTMLCollection
.
HTMLCollection.prototype.each = function(callback){
for(var i=0; i<this.length; i++) callback(this[i]);
};
document.getElementsByTagName('div').each(function(div){
div.innerHTML = "poo";
});
Если вы используете querySelectorAll
, вы можете прикрепить ту же функцию к NodeList
NodeList.prototype.each = function(callback){
for(var i=0; i<this.length; i++) callback(this[i]);
};
document.querySelectorAll('div').each(function(div){
div.innerHTML = "podo";
});
Чтобы успокоить chanters (см. комментарии), я укажу, что если это для библиотеки, которую вы пишете, или если она будет использоваться вместе с библиотекой, которая могла бы ее перезаписать, очевидно, вы бы хотели рассмотреть другие методы.
Fiddle: https://jsfiddle.net/er5amk8j/
Но вы также используете $.each()
в сомнительном ключе в своем примере. Намного проще и быстрее обращаться к элементам с помощью this
.
$('button').each(function(i) {
$(this).css('background', 'red');
});
Самая простая замена - это использование простых закрытий функций, но это не очень.
var $buttons = $('button');
for(var i = 0; i < $buttons.length; i++){
(function(i){
$buttons.eq(i).css('background', 'red');
})(i);
}
Или для установки this
используйте .call()
для вызова функции.
var $buttons = $('button');
for(var i = 0; i < $buttons.length; i++){
(function(i){
$(this).css('background', 'red');
}).call($buttons[i], i);
}