2016-11-28 25 views
16

在jQuery中,我們有一個功能,每一個這樣的什麼是JavaScript中jQuery的each()函數的替代品?

$('button').each(function(i) { 
    $('button').eq(i).css('background', 'red'); 
}); 

我們如何能夠用普通的JavaScript將這段代碼?

+0

那麼'Array.prototype.forEach()',但它本身並不能代替*那*代碼。 – Pointy

+0

只需使用'for ... of'循環。 – Bergi

回答

24

querySelectorAll()

瀏覽器的DOM的選擇有多種選擇方式,從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

一個很常見的方式做一個功能的循環結構是借用Array.prototypeforEach方法,並使用函數的在元素集合上調用它方法是這樣的:

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()借用可以縮短d如果在應用程序的早期階段,使用函數原型的bind()方法將.forEach()方法綁定到的值.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 (請參閱文檔鏈接)將其修補到傳統瀏覽器中。

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


Transpiling現代代碼

對於上面的例子中需要最現代的瀏覽器,可有transpilers(例如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通常不需要,因爲你已經擁有的元素作爲參數。

+0

不錯。但在jQuery的'$(...)。each()'中,'this'將指向元素。 – haim770

+0

@ haim770:的確如此,儘管我認爲OP只是想知道如何在JS中做這樣的循環,而不一定完全按照它在jQuery中的表現。 – 2016-11-28 21:17:05

+1

@squint你爲什麼使這是一個CW? –

3
var buttons = document.querySelectorAll("button"); 
for(var x in buttons){ 
    var e = buttons[x]; 
    e.innerHTML="stuff"; 
} 

as squint指出,它應該是buttons [x]和var x。 對不起。

+0

哎呀忘了關於e =按鈕[x] – MyNameIsUser9123

5

您可以使用函數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"; 
} 

編輯:我意識到這不是jQuery的每個函數的工作原理。 OP沒有說明他想特別地看到,只是一種用JS完成$.each()功能的方法(因爲有很多可能性)。這個例子只是一個使用非常基本概念的簡單方法。

3

受更多瀏覽器支持,因爲它不使用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(見註釋),我會規定,如果這是你寫一個庫,或者如果將它與可能覆蓋它的庫一起使用,顯然你會想考慮其他方法。

小提琴:https://jsfiddle.net/er5amk8j/

+1

[不要修改你不擁有的對象。](http://stackoverflow.com/q/6223449/3853934) –

+0

@Gothdo不要做一攬子聲明,只適用於某些情況下,否則根本沒有意義。 –

+0

如果您認爲這不適用於您的情況,請解釋。 –

2

但你也在你的榜樣可疑的方式使用$.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); 
} 
+0

在第二個例子中實際上並不需要IIFE,因爲在循環中立即使用'i',而不是稍後在回調中使用。儘管你對OP的技術是正確的。在循環中反覆調用'$('按鈕')'會很慢。 – 2016-11-29 13:22:27

+0

@squint你是對的。但我已經擴展了「Michael Hamilton」的答案,目的是表明雖然結果相同,但它不是取代'.each()'的正確方法。 – Bizniztime