如何筛选QuerySelectorAll返回的元素

时间:2011-07-22 13:57:17

标签: javascript

我正在开发一个javascript libarary,我使用这个函数来匹配元素:

$ = function (a)
{
    var x;
    if (typeof a !== "string" || typeof a === "undefined"){ return a;}

    //Pick the quickest method for each kind of selector
    if(a.match(/^#([\w\-]+$)/))
    {
        return document.getElementById(a.split('#')[1]);
    }
    else if(a.match(/^([\w\-]+)$/))
    {
        x = document.getElementsByTagName(a);
    }
    else
    {
        x = document.querySelectorAll(a);
    }

    //Return the single object if applicable
    return (x.length === 1) ? x[0] : x;
};

在某些情况下,我希望过滤此功能的结果,例如选择div span,或#id div或其他一些相当简单的选择器。

如何过滤这些结果?我可以创建一个文档片段,并在该片段上使用querySelectorAll方法,还是必须使用手动字符串操作?

我只关心现代浏览器和IE8 +。

如果您想查看我的图书馆的其余部分,请点击此处:https://github.com/timw4mail/kis-js

编辑:

为了澄清,我希望能够做一些像$ _(选择器).children(other_selector)这样的东西,并返回匹配该选择器的子元素。

编辑:

所以这是我对最简单的选择器的潜在解决方案:

tag_reg = /^([\w\-]+)$/;
id_reg = /#([\w\-]+$)/;
class_reg = /\.([\w\-]+)$/;

function _sel_filter(filter, curr_sel)
{
    var i,
        len = curr_sel.length,
        matches = [];

    if(typeof filter !== "string")
    {
        return filter;
    }

    //Filter by tag
    if(filter.match(tag_reg))
    {
        for(i=0;i<len;i++)
        {
            if(curr_sell[i].tagName.toLowerCase() == filter.toLowerCase())
            {
                matches.push(curr_sel[i]);
            }
        }
    }
    else if(filter.match(class_reg))
    {
        for(i=0;i<len;i++)
        {
            if(curr_sel[i].classList.contains(filter))
            {
                matches.push(curr_sel[i]);
            }
        }
    }
    else if(filter.match(id_reg))
    {
        return document.getElementById(filter);
    }
    else
    {
        console.log(filter+" is not a valid filter");
    }

    return (matches.length === 1) ? matches[0] : matches;

}

它采用div标记,id或类选择器,并返回带有curr_sel参数的匹配元素。

我不想诉诸完整的选择引擎,那么有更好的方法吗?

4 个答案:

答案 0 :(得分:19)

我认为我的问题不对。为什么要“过滤”querySelectorAll()的结果,实际上,这是某种过滤器本身。如果您查询div span或更好#id div,那么这些结果已经过滤了,不是吗?

但是,您可以将Array.prototype.filter应用于querySelectorAll的静态结果,如下所示:

var filter   = Array.prototype.filter,
    result   = document.querySelectorAll('div'),
    filtered = filter.call( result, function( node ) {
        return !!node.querySelectorAll('span').length;
    });

该代码首先使用querySelectorAll()来查询文档中的所有<div>个节点。然后,它将过滤包含至少一个<div>的{​​{1}}个节点。该代码没有多大意义,仅用于演示目的(以防某些SO成员想要创建donk评论)

<强>更新

您还可以使用<span>进行过滤。我还要说明元素是Element.compareDocumentPositiondisconnectedfollowing还是preceding。见MDC .compareDocumentPosition()

答案 1 :(得分:3)

2019年最简洁的方法是使用spread syntax ...加上数组文字[...],它与querySelectorAll返回的NodeList等可迭代对象非常适用:

[...document.querySelectorAll(".myClass")].filter(el=>{/*your code here*/})

答案 2 :(得分:2)

支持qsa的某些浏览器也支持非标准matchesSelector方法,例如:

element.webkitMatchesSelector('.someSelector')

...将返回一个布尔值,表示element是否与提供的选择器匹配。因此,您可以迭代集合,并应用该方法,保留积极的结果。

在没有matchesSelector的浏览器中,您可能需要构建自己的基于选择器的方法,类似于您正在构建的选择器引擎。

答案 3 :(得分:2)

  

注意:NodeList不是真正的数组,也就是说它没有   数组方法,例如slice,some,map等。将其转换为   数组,请尝试Array.from(nodeList)。

ref:https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll

例如:

let highlightedItems = userList.querySelectorAll(".highlighted");

let items = Array.from(highlightedItems);

items.filter((item) => {
 //...
})