Child selector using `querySelectorAll` on a DOM c

2019-02-02 05:31发布

问题:

Let's presume you got a list with nested child lists.

<ul>
    <li></li>
    <li>
        <ul>
            <li></li>
            <li></li>
        </ul>
    </li>
    <li></li>
</ul>

And use document.querySelectorAll() to make a selection:

var ul = document.querySelectorAll("ul");

How can i use the ul collection to get the direct child elements?

ul.querySelectorAll("> li"); 
// Gives 'Error: An invalid or illegal string was specified'

Let's presume ul is cached somehow (otherwise i could have done ul > li directly).

In jQuery this works:

$("ul").find("> li");

But it doesn't in native querySelectorAll. Any solutions?

回答1:

The correct way to write a selector that is "rooted" to the current element is to use :scope.

ul.querySelectorAll(":scope > li");

See my answer here for an explanation and a robust, cross-browser solution: https://stackoverflow.com/a/21126966/1170723



回答2:

Because the ul returned is a NodeList, it doesn't implicitly loop over its contents like a jQuery collection. You'd need to use ul[0].querySelectorAll() or better still select the ul with querySelector().

Besides that, querySelectorAll() won't take a > and work from its current context. However, you can get it to work using lazd's answer (though check the browser compatibility), or any of these workarounds (which should have no browser issues)...

[].filter.call(ul.querySelectorAll("li"), function(element){
     return element.parentNode == ul;
}); 

jsFiddle.

This will select all li elements that are descendants of your ul, and then remove the ones which are not direct descendants.

Alternatively, you could get all childNodes and then filter them...

[].filter.call(ul.childNodes, function(node) {
    return node.nodeType == 1 && node.tagName.toLowerCase() == 'li';
});

jsFiddle.



回答3:

You need to iterate over the NodeList returned by document.querySelectorAll() and then call element.querySelectorAll() for each element in that list.