从右到左选择:位置伪类

位置伪类好像天生克从右到左的选择器,处理起来非常复杂,大抵有以下三种情况

1、位置选择器出现群组的最后面。这种情况相对简单,我们先跳过它,取得节点后再进行过滤,如“"div span:eq(0)”

        for (var selector ; selector = selectors[i++];) {
        /**********略**********/
        /*遍历DOM树,收集符合条件的节点*/
        }
        /*如果选择器群组包含位置伪类,则进行筛选*/
        if(pos && obj.nodes.length ){
            obj.nodes = posFilter(obj.nodes,pos);
        }

posFilter函数:

    var posFilter = function(nodes,pos){
        var match = pos.match(reg_pseudo), name = match[1],value = match[3],node,ri = 0,i = 0,result = [],
        filter = dom._filters[name]
        value = (value === ""|| value === void 0) ? nodes.length - 1 : ~~value;
        for (; node = nodes[i];){
            if(filter(i++, value) )
                result[ri++] = node;
        }
        return result;
    }

2、位置伪类位于并联选择器的两边,如“div:eq(0),#aa.class”

            if(selector === ","){
                if(pos && obj.nodes.length ){//处理位置伪类
                    obj.nodes = posFilter(obj.nodes,pos)
                    pos = false;
                }
                result = result.concat(obj.nodes);
                //处理逗号另一边的选择器群组
                match  = getCandidates(selectors,context,i);
                i      = match[1];
                pos    = match[2];
                if(!match[0].length){
                    i = indexOf(selectors,",",i);
                    if(i===-1){
                        break;
                    }
                }
                obj = {
                    set:{},
                    proxy:proxyViaSelf,
                    nodes:match[0]
                }
                flag_sort = true;
            }

如果位置伪类出现在中间并且不靠近并联选择器,如“form span:eq(1) strong”。毫无疑问,我们只能用递归收拾它了。

//比如form span:eq(1) strong
        ":":function(selector,obj,flag_xml,flag_not,doc,selectors,i){//★★★★(9)伪类
            var match = selector.match(reg_pseudo), name = match[1];
            if(one_position[name]){//位置伪类
                var last = indexOf(selectors,",",i);
                last = last === -1 ? selectors.length :last;
                obj.args = [dom.query(selectors.slice(i-1,last),doc,flag_xml,flag_not)];//我们在这里筛选出匹配“form span:eq(1)”的节点
                obj.filter = function(nodes){//过滤器,用于strong与eq(0)之间的后代选择器对应的代理器
                    return indexOf(nodes,this) > -1;
                },
                obj.i = last;
            }
        }

2010.12.16日补充

如果我们对原来的选择器群组做一些调整,或者能简化这逻辑,如div:eq(0)变成:eq(0)^div,那么从右到左选择时,自然成为div,:eq(0)的选择顺序。不用说,我们又需要一个强大的正则来处理它。

原文地址:https://www.cnblogs.com/rubylouvre/p/1905166.html