Is it possible to get elements that have one of the specified classes? This is not the same as getting elements that have all of the specified classes.
For example, I want to capture all elements whose class list contains either one
, two
, or three
.
Maybe something like this:
var oneTwoThree = document.getElementsByClassName("one, two, three");
I also do not want to use jQuery. Is the only option to getElementsByClassName
for each class and combine them?
The JavaScript getElementsByClassName is used to get all the elements that belong to a particular class. When the JavaScript get element by class name method is called on the document object, it searches the complete document, including the root nodes, and returns an array containing all the elements.
getElementsByClassName() The getElementsByClassName method of Document interface returns an array-like object of all child elements which have all of the given class name(s).
The getElementsByClassName() method returns an array-like of objects of the child elements with a specified class name. The getElementsByClassName() method is available on the document element or any other elements. The method returns the elements which is a live HTMLCollection of the matches elements.
To select a specific HTML class using JavaScript, we need to target it and then store it as a variable. Here is the one line of JavaScript we need to target this element and store it as a variable: Code from a text editor: const vanillaDescription = document. querySelector('.
querySelector
accepts pretty much any CSS selector:
var oneTwoThree = document.querySelectorAll('.one, .two, .three');
I also do not want to use jQuery. Is the only option to getElementsByClassName for each class and combine them?
By using querySelectorAll
(as answered), it will search and do the combining for you.
IE9+ {IE8 (CSS2 selectors only}
Otherwise, getElementsByClassName
is not the only method available to you, it's not even available on some older browsers (IE9+, FF3+).
But pretty much any other method that you could use would require that you combine the results. So, just as a demonstration I have created a few examples for you.
Define the white spaces as per HTML4.01 class attribute
"This attribute assigns a class name or set of class names to an element. Any number of elements may be assigned the same class name or names. Multiple class names must be separated by white space characters."
var whiteSpaces = '[\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]';
Define the space characters as per HTML5 3.2.5.7 The class attribute
Every HTML element may have a class attribute specified.
The attribute, if specified, must have a value that is a set of space-separated tokens representing the various classes that the element belongs to.
The classes that an HTML element has assigned to it consists of all the classes returned when the value of the class attribute is split on spaces. (Duplicates are ignored.)
Assigning classes to an element affects class matching in selectors in CSS, the getElementsByClassName() method in the DOM, and other such features.
There are no additional restrictions on the tokens authors can use in the class attribute, but authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content.
The className and classList IDL attributes, defined in the DOM specification, reflect the class content attribute. [DOM]"
var whiteSpaces = '[ \n\r\t\f]';
Define start an end echaratcers
var starts = '(^|' + whiteSpaces + ')',
ends = '(' + whiteSpaces +'|$)';
Cross browser (DOM walker)
function walkTheDOM(node, func) {
func(node);
node = node.firstChild;
while (node) {
walkTheDOM(node, func);
node = node.nextSibling;
}
}
function getElementsByClassName1(node, className) {
var regex = new RegExp(starts + className + ends),
results = [];
walkTheDOM(node, function (currentNode) {
if (regex.test(currentNode.className)) {
results.push(currentNode);
}
});
return results;
}
Cross browser (getElementsByClassName)
function getElementsByClassName2(node, className) {
var array = [],
regex = new RegExp(starts + className + ends),
elements = node.getElementsByTagName("*"),
length = elements.length,
i = 0,
element;
while (i < length) {
element = elements[i];
if (regex.test(element.className)) {
array.push(element);
}
i += 1;
}
return array;
}
Modern browser (IE9+)
function getElementsByClassName3(node, className) {
var results = [],
treeWalker = document.createTreeWalker(
node,
NodeFilter.SHOW_ELEMENT, {
acceptNode: function (thisNode) {
var accept = NodeFilter.FILTER_SKIP;
if (thisNode.classList.contains(className)) {
accept = NodeFilter.FILTER_ACCEPT;
}
return accept;
}
}, false);
while (treeWalker.nextNode()) {
results.push(treeWalker.currentNode);
}
return results;
}
Modern browser (IE9+)
function getElementsByClassName4(node, className) {
return Array.prototype.slice.call(document.getElementsByClassName(className));
}
Cross browser Array.indexOf
function indexOf(array, searchElement, fromIndex) {
var length = array.length,
val = -1,
index;
if (length !== 0) {
if (arguments.length > 2) {
fromIndex = fromIndex >> 0;
} else {
fromIndex = 0;
}
if (fromIndex < length) {
if (fromIndex < 0) {
fromIndex = length - Math.abs(fromIndex);
}
if (fromIndex < 0) {
fromIndex = 0;
}
for (index = fromIndex; index < length; index += 1) {
if (index in array && searchElement === array[index]) {
val = index;
break;
}
}
}
}
return val;
}
Cross browser Array.filter
function filter(array, fn, thisArg) {
var length = array.length,
arr = [],
index,
element;
for (index = 0; index < length; index += 1) {
if (index in array) {
element = array[index];
if (fn.call(thisArg, element, index, array)) {
arr.push(element);
}
}
}
return arr;
};
Combining the results and maintaining order
function getElements(node, classes, func) {
if (typeof classes === 'string') {
classes = classes.split(/\s*,\s*/);
}
var length = classes.length,
results = [],
index,
name;
for (index = 0; index < length; index += 1) {
name = classes[index];
if (name.charAt(0) === '.') {
name = name.slice(1);
}
results = results.concat(func(node, name));
}
return filter(results.reverse(), function (element, index, arr) {
return index <= indexOf(arr, element);
}).reverse();
}
Test
<div class='A'></div>
<div class='B'></div>
<div class='A B'></div>
<div class='C'></div>
console.log(getElements(document, '.A, .B', getElementsByClassName1));
console.log(getElements(document, '.A, .B', getElementsByClassName2));
console.log(getElements(document, '.A, .B', getElementsByClassName3));
console.log(getElements(document, '.A, .B', getElementsByClassName4));
console.log(document.querySelectorAll('.A, .B'));
On jsFiddle
And finally a performace comparison for you, on jsPerf
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With