我有这段代码,其中我试图接受像classList
和querySelector
这样的JS函数,但由于处理程序的循环等问题,它最终会变得非常冗长:
var cg = document.querySelectorAll('.control-group'),
cgL = cg.length;
while (cgL--) {
var _cg = cg[cgL],
inputs = _cg.querySelectorAll('input'),
i = 0;
for (l = inputs.length; i < l; i++) {
inputs[i].addEventListener('focus', focus, false);
inputs[i].addEventListener('blur', focus, false);
}
function focus() {
_cg.classList.toggle('focus');
}
}
小提琴:http://jsfiddle.net/YGeh5/3/
有没有办法避免绕过NodeList来为每个元素分配一个事件处理程序?
答案 0 :(得分:3)
您可以使用Array.forEach()
。但是,由于您返回了NodeList,并且其原型中没有forEach()
,因此您需要使用.call
并将其作为上下文提供。
然而,it's ES5. Most modern browsers have it though。另外,the polyfill is also a loop,只是从你身上抽象出来。
Here's your code,几乎直接转换为使用forEach()
:
var cg = document.querySelectorAll('.control-group');
Array.prototype.forEach.call(cg, function (group) {
var inputs = group.querySelectorAll('input');
function focus() {
group.classList.toggle('focus');
}
Array.prototype.forEach.call(inputs, function (input) {
input.addEventListener('focus', focus, false);
input.addEventListener('blur', focus, false);
});
});
答案 1 :(得分:2)
您可以在'.control-group'上委派事件,然后通过e.target过滤输入。它还将在大量输入上使用更少的内存。工作示例:http://jsfiddle.net/RZhTj/1/
var cg = document.querySelectorAll('.control-group'),
cgL = cg.length;
while (cgL--) {
var _cg = cg[cgL];
_cg.addEventListener('focus', focus, true);
_cg.addEventListener('blur', focus, true);
function focus(e) {
if (e.target instanceof HTMLInputElement) _cg.classList.toggle('focus');
}
}
答案 2 :(得分:1)
如果浏览器有Array#forEach
,您可能希望使用forEach迭代NodeList。首先必须将其转换为数组。一种方法是使用Array.prototype.slice。
Array.prototype.slice.call(_cg.querySelectorAll('input'), 0).forEach(function (input) {
input.addEventListener('focus', focus, false);
});
或者只是在NodeList上调用Array.prototype.forEach:
Array.prototype.forEach.call(_cg.querySelectorAll('input'), function (input) {
input.addEventListener('focus', focus, false);
});
请注意,您可以将两个querySelectorAll分组到一个查询中。
您还可以将焦点闭包移出循环,因为它实际上不需要对元素的引用。
你的整个代码变成了:
function focus(event) {
event.target.classList.toggle('focus');
}
Array.prototype.forEach.call(document.querySelectorAll('.control-group input'), function (input) {
input.addEventListener('focus', focus, false);
input.addEventListener('blur', focus, false);
});