Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get elements by class A or B in JavaScript

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?

like image 931
CookieEater Avatar asked Feb 18 '14 12:02

CookieEater


People also ask

Can you get element by class in JavaScript?

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.

What does getElementsByClassName () function return?

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).

Is there a get element by class?

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.

How do you target a class in JavaScript?

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('.


2 Answers

querySelector accepts pretty much any CSS selector:

var oneTwoThree = document.querySelectorAll('.one, .two, .three');
like image 52
Tibos Avatar answered Oct 19 '22 22:10

Tibos


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

like image 28
Xotic750 Avatar answered Oct 19 '22 21:10

Xotic750