带有两个类的 getElementsByClassName()

有没有可能只使用 getElementsByClassName()一次就可以得到类 a 或者 b的所有元素? 我更喜欢普通的 JavaScript。

92408 次浏览

You can't do it with getElementsByClassName() method instead use querySelectorAll() method with comma separated class selectors.

document.querySelectorAll('.a,.b')

You can pass more than one class name to getElementsByClassName() by separating them with spaces:

var elems = document.getElementsByClassName("class1 class2 class3");

Now, this differs from the .querySelectorAll(".class1,.class2,.class3") approach in that it applies a conjunction, not a disjunction — "and" instead of "or". Thus

var elems = document.getElementsByClassName("class1 class2 class3");

is like

var elems = document.querySelectorAll(".class1.class2.class3");

Sometimes you want one, sometimes you want the other. It's definitely true that .querySelectorAll() gives you much more flexibility.

Just to add a bit more support, here is a version that is compatible with older versions of IE and uses pure vanilla js :

function getElementsByClassNameOr(root, classNameString) // classNameString like '.a, .b' don't forget the comma separator
{
var arr = [],
rx = new RegExp('(^|[ \n\r\t\f])' + classNameString + '([ \n\r\t\f]|$)'),
elements = root.getElementsByTagName("*");


var elem;


for (i=0 ; i < elements.length ; i++) {
elem = elements[i];
if (rx.test(elem.className)) {
arr.push(elem);
}


}


return arr; // will contain all the elements that have one of the classes in ClassNameString, root can be document or a div.
}

No, you can't achieve that with only one document.getElementsByClassName() call. That function returns elements which have all of the classes specified in the first argument as a space-separated string.

There are two possible solution. First is to use document.querySelectorAll() instead, which uses CSS selectors.

document.querySelectorAll(".a, .b")

The second solution is to call document.getElementsByClassName() twice, turn the results into arrays using Array.from() and merge them using Array.prototype.concat(). To avoid duplicates (for example when element has both a and b class), you have to create a new Set from that array, and then turn it back to array using Array.from().

const classA = Array.from(document.getElementsByClassName("a"))
,classB = Array.from(document.getElementsByClassName("b"))
,result = Array.from(new Set(classA.concat(classB)))

See demo below:

console.log("first solution", document.querySelectorAll(".a, .b"))


const classA = Array.from(document.getElementsByClassName("a"))
,classB = Array.from(document.getElementsByClassName("b"))
,result = Array.from(new Set(classA.concat(classB)))


console.log("second solution", result)
<div class="a"></div>
<div class="b"></div>
<div class="a b"></div>
<div class="c"></div>

Note that the first solution gives an array-like NodeList object, whereas the second gives just an array.