如果是从左到右,我们想过滤一些节点,就用现在手头上的节点就行了,但从右到左,我们就需要根据这些节点的父亲、孩子、兄弟进行过滤,而且过滤后,这些用作比较的节点不能丢弃掉,它们可以还要用于下一次的过滤。这样就存在一个代理关系,我们需要一些代理器来干这事情。当然像div.aaa是不需要代理器,但div div.aaa就需要了。在从左到右的情况下,我们所有说的关系选择器,主要有亲子兄长与相邻三种,遇到后代选择器,我们可以转化为通配符选择器与标签选择器。而在从右到左,关系选择器就包括后代通配符亲子兄长相邻五种,通配符实质是一种带层次关系的后代选择器。
//取得候选集的共同父节点的合集
var getParent = function(testee,result,yess,pid){
while((testee = testee.parentNode)){
pid = testee.uniqueID || (testee.uniqueID = dom.UID++);
if(yess[pid]){
result = testee
}
}
return result;
}
var iterators = {
current:function(nextset){
var set = this, nodes = this.nodes,tagName = this.tagName, filter = this.filter,args = this.args,
result = [], testee, uid;
for(var i = 0,ri = 0, node;node = nodes[i++];){
uid = node.uniqueID || (node.uniqueID = dom.UID++);
testee = set[uid] || node;
if((!tagName || tagName === testee.nodeName) && (!filter || filter.apply(testee,args))){
result[ri++] = node;
nextset[uid] = testee;
}
}
nextset.nodes = result;
},
parent:function(nextset){
var set = this, nodes = this.nodes,tagName = this.tagName, filter = this.filter,args = this.args,
result = [], yess = {}, testee, uid, pid;
for(var i = 0,ri = 0, node; node = nodes[i++];){
uid = node.uniqueID || (node.uniqueID = dom.UID++);
testee = set[uid] || node;
while((testee = testee.parentNode) && testee.nodeType === 1 ){
pid = testee.uniqueID || (testee.uniqueID = dom.UID++);
if(yess[pid]){
result[ri++] = node;
nextset[uid] = testee;
break;
}
if((!tagName || tagName === testee.nodeName) && (!filter || filter.apply(testee,args))){
yess[pid] = result[ri++] = node;
nextset[uid] = testee;
}
break;
}
}
nextset.nodes = result;
},
iterators.parents = function (nextset) {
var set = this, nodes = this.nodes, tagName = this.tagName, filter = this.filter, args = this.args, level = this.level, _level, result = [], testee, uid, pid, yess = {};
for (var i = 0, ri = 0, node; node = nodes[i++];) {
uid = node.uniqueID || (node.uniqueID = dom.UID++);
testee = set[uid] || node;
while ((testee = testee.parentNode)) {
if (testee.nodeType === 1) {
if (level) {
_level = level;
while (_level-- && (testee = testee.parentNode)) {
}
if (!testee) {
break;
}
}
pid = testee.uniqueID || (testee.uniqueID = dom.UID++);
if (yess[pid]) {
result[ri++] = node;
nextset[uid] = nextset[yess[pid].uniqueID];
break;
}
if ((!tagName || tagName === testee.nodeName) &&
(!filter || filter.apply(testee, args))) {
yess[pid] = result[ri++] = node;
nextset[uid] = getParent(testee, result, yess, pid);
break;
}
}
}
}
nextset.nodes = result;
}
border:function(nextset){
var set = this, nodes = this.nodes,tagName = this.tagName, filter = this.filter,args = this.args,
result = [], testee, uid;
for(var i = 0,ri = 0, node;node = nodes[i++];){
uid = node.uniqueID || (node.uniqueID = dom.UID++);
testee = set[uid] || node;
while((testee = testee.previousSibling) && testee.nodeType === 1){
if((!tagName || tagName === testee.nodeName) && (!filter || filter.apply(testee,args))){
result[ri++] = node;
nextset[uid] = testee;
}
break;
}
}
nextset.nodes = result;
},
borders:function(nextset){
var set = this, nodes = this.nodes,tagName = this.tagName, filter = this.filter,args = this.args,
result = [], yess = {}, testee, uid, pid;
for(var i = 0,ri = 0, node;node = nodes[i++];){
uid = node.uniqueID || (node.uniqueID = dom.UID++);
testee = set[uid] || node;
while((testee = testee.previousSibling) && testee.nodeType === 1){
pid = testee.uniqueID || (testee.uniqueID = dom.UID++);
if(yess[pid]){
result[ri++] = node;
nextset[uid] = testee
break;
}
if((!tagName || tagName === testee.nodeName) && (!filter || filter.apply(testee,args))){
yess[pid] = result[ri++] = node;
nextset[uid] = testee;
break;
}
}
}
nextset.nodes = result;
}
}
它们几个好相似,正在考虑是否动态生成它们……
<!doctype html> <html> <head> <title>从右到左选择:测试样式(针对关系选择器) </title> <meta http-equiv="X-UA-Compatible" content="IE=8" /> <script src="dom/lib/queryv41.js"></script> <style> span ~span~span{ color: red; } </style> <script> window.onload = function(){ var show = function(sets){ var array = [] for(var i in sets){ array.push(sets[i].innerHTML) } alert(array) } //"tr~tr~tr" //div span~ span //div+div span //tr+tr+tr // var els = dom.query("span~span~span"); // alert(els.length) // show(els) } </script> </head> <body> <table class="filament_table" cellspacing="0" width="700" rules="cols" border="1"> <col class="grey" width="30%"></col> <col class="yellow"></col> <thead> <tr> <th>property</th> <th>value</th> </tr> </thead> <tbody> <tr> <td>display</td> <td>inline-block</td> </tr> <tr> <td>height</td> <td>any value</td> </tr> <tr> <td>float</td> <td>left or right</td> </tr> <tr> <td>position</td> <td>absolute</td> </tr> <tr> <td>width</td> <td>any value</td> </tr> <tr> <td>writing-mode</td> <td>tb-rl</td> </tr> <tr> <td>zoom</td> <td>any value</td> </tr> </tbody> </table> <div id="parent1" class="ccc bbb"> <span>11111111</span> </div> <div> <span>54354435</span> <div id="parent2"> <span class="aaa bbb">aaaaaaaaa</span> <span>bbbbbbb</span> <strong>ccccccc</strong> <span>dddddddd</span> <div> <span>44444444</span> </div> </div> </div> <span id="prev">555555555</span> </body> </html>运行代码
用时间截代替UID的筛选功能
选择div div div
3
3
后代
var fathers = function () {
var querytime = dom.querytime //new Date - 0
var nodes = this[0],set = this[1],args = this[4], filter = this[5],_set = [], _nodes = [], i = 0, ri = 0,node, testee;
while ((testee = set[i])) {
node = testee; //node至始自终从候选集中甄选,testee则从set的元素的长辈里甄选
while ((testee = testee.parentNode)) {
if (testee.querytime === querytime) {
_set[ri] = testee;
_nodes[ri++] = nodes[i];
break;
}
if (testee.nodeName === "DIV") {
testee.querytime = querytime
_set[ri] = testee;
_nodes[ri++] = nodes[i];
break;
}
}
i++;
}
this[0] = _nodes;
this[1] = _set;
this.length = 3;
}
亲子
var father = function () {
var querytime = dom.querytime;
var nodes = this[0], set = this[1], args = this[4], filter = this[5], _set = [], _nodes = [], i = 0, ri = 0, node, testee;
while ((testee = set[i])) {
node = testee;
while ((testee = testee.parentNode)) {
if (testee.querytime === querytime) {
_set[ri] = testee;
_nodes[ri++] = node;
break;
}
if (testee.nodeName === "DIV") {
testee.querytime = querytime
_set[ri] = testee;
_nodes[ri++] = node;
}
break;
}
i++;
}
this[0] = _nodes;
this[1] = _set;
this.length = 3;
}
2011.1.26
var border = function (expr, set, flag_xml) {
var selector, filter = Rage.filter;
expr = expr.replace(reg_tag, function ($) {
selector = $ === '*' ? true : flag_xm ? $ : $.toUpperCase();
return '';
});
for (var i = 0, n = set.length; i < n; i++) {
if (testee = set[i]) {
while ((testee = testee.previousSibling) && testee.nodeType !== 1) {};
testee = testee && testee.nodeName === selector && testee || false;
}
}
expr && filter.call(null, expr, set, true);
}
var parent = function (expr, set, flag_xml) {
var selector, filter = Rage.filter;
expr = expr.replace(reg_tag, function ($) {
selector = $ === '*' ? true : flag_xm ? $ : $.toUpperCase();
return '';
});
for (var i = 0, n = set.length; i < n; i++) {
if (testee = set[i]) {
testee = testee.parentNode;
testee = testee && testee.nodeName === selector && testee || false;
}
}
expr && filter.call(null, expr, set, true);
}
var borders = function (expr, set, flag_xml) {
var selector, filter = Rage.filter,_filter = Rage._filter,flag_fn = false,old = expr,prop = 'previousSibling';
expr = expr.replace(reg_first, function ($) {
if (reg_tag.test($)) {
selector = $ === '*' ? true : flag_xm ? $ : $.toUpperCase();
} else {
selector = $;
flag_fn = true;
}
return '';
});
if (expr === old) {
throw old + '存在语法错误';
}
_filter.call(null, selector, set, prop, flag_fn);
expr && filter.call(null, expr, set, true);
}
var parents = function (expr, set, flag_xml) {
var selector, filter = Rage.filter,_filter = Rage._filter, flag_fn = false,old = expr, prop = 'parentNode';
expr = expr.replace(reg_first, function ($) {
if (reg_tag.test($)) {
selector = $ === '*' ? true : flag_xm ? $ : $.toUpperCase();
} else {
selector = $;
flag_fn = true;
}
return '';
});
if (expr === old) {
throw old + '存在语法错误';
}
_filter.call(null, selector, set, prop, flag_fn);
expr && filter.call(null, expr, set, true);
}