什么是JavaScript中jQuery的each()函数的替代品?
在jQuery中,我们有一个功能,每一个这样的什么是JavaScript中jQuery的each()函数的替代品?
$('button').each(function(i) {
$('button').eq(i).css('background', 'red');
});
我们如何能够用普通的JavaScript将这段代码?
与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.prototype
的forEach
方法,并使用函数的在元素集合上调用它方法是这样的:
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
通常不需要,因为你已经拥有的元素作为参数。
不错。但在jQuery的'$(...)。each()'中,'this'将指向元素。 – haim770
@ haim770:的确如此,尽管我认为OP只是想知道如何在JS中做这样的循环,而不一定完全按照它在jQuery中的表现。 – 2016-11-28 21:17:05
@squint你为什么使这是一个CW? –
var buttons = document.querySelectorAll("button");
for(var x in buttons){
var e = buttons[x];
e.innerHTML="stuff";
}
as squint指出,它应该是buttons [x]和var x。 对不起。
哎呀忘了关于e =按钮[x] – MyNameIsUser9123
您可以使用函数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()
功能的方法(因为有很多可能性)。这个例子只是一个使用非常基本概念的简单方法。
受更多浏览器支持,因为它不使用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(见注释),我会规定,如果这是你写一个库,或者如果将它与可能覆盖它的库一起使用,显然你会想考虑其他方法。
[不要修改你不拥有的对象。](http://stackoverflow.com/q/6223449/3853934) –
@Gothdo不要做一揽子声明,只适用于某些情况下,否则根本没有意义。 –
如果您认为这不适用于您的情况,请解释。 –
但你也在你的榜样可疑的方式使用$.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);
}
在第二个例子中实际上并不需要IIFE,因为在循环中立即使用'i',而不是稍后在回调中使用。尽管你对OP的技术是正确的。在循环中反复调用'$('按钮')'会很慢。 – 2016-11-29 13:22:27
@squint你是对的。但我已经扩展了“Michael Hamilton”的答案,目的是表明虽然结果相同,但它不是取代'.each()'的正确方法。 – Bizniztime
那么'Array.prototype.forEach()',但它本身并不能代替*那*代码。 – Pointy
只需使用'for ... of'循环。 – Bergi