从右到左选择:位置伪类
位置伪类好像天生克从右到左的选择器,处理起来非常复杂,大抵有以下三种情况
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)的选择顺序。不用说,我们又需要一个强大的正则来处理它。
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年