这个以前已经研究过了,但嫌速度不够快,重新搞了一个。现在略略重申一下问题,比如有一个节点集合[a,b,c,d,e],其中,a是b的父节点, d是b的父节点,我要的结果是去掉这些存在包含关系的节点中的被包含者,换言之,最终得到[c,d,e]。
这里可能用到contains函数:预先列出来吧。
//http://www.cnblogs.com/rubylouvre/archive/2009/10/14/1583523.html var contains = function(ancestor,node) { if (node.compareDocumentPosition) return (node.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(node) && ancestor !== node; while (node = node.parentNode) if (node == ancestor) return true; return false; }
如果得到不存在包含关系的祖先节点集合对后代选择器与通配符选择器的实现至关重要,因为它涉及去重与排序问题。以前我不懂这一点,一古脑地冲一去,得到所有后代再进行排序去重,慢死了。我新一代的选择器绝然不能走这老路了。
当然,像我这样想的,我绝对不是第一位。如百度的Fox选择器就存在这么一个函数:
/** * 得到一个树集合中第一层级的节点 * @method getFirstLevelNodes * @static * @param {HTMLElements|Array} 树集合节点 * @return {Array} 返回第一层的节点集合数组 */ Fox.getFirstLevelNodes = function(nodes) { for (var i=1; i < nodes.length; i++) { if (Fox.contains(nodes[i-1], nodes[i])) { //除重,复杂度O(N)。 //如果dom里前者包含后者,则移者后者 //当前循环标记-1 //结果将是 //第一轮:[1,3,4,5,6], i=1 //第二轮:[1,4,5,6] i=1 //第三轮:[1,5,6] i=1 //第四轮:[1,6] i=1 //第五轮:[1] i=1 nodes.splice(i,1); i--; } } return nodes; };
但这个函数存在一个致命的缺陷,就是要求nodes为节点数组,而不是节点集合。要知道像节点集合转换为纯数组可不是什么一蹴而成的事,可恶的IE的节点集合不能轻易用Array.prototype.slice.call就转换掉,而且逐一放进空数组时,还要留意是否混入了注释节点。另外,每次得到元素节点就进行转换太不现实了。因此我的祖先获取函数必须支持节点集合。下面是我新的函数:
// by 司徒正美 取得不存在包含关系的祖先节点集合 // http://www.cnblogs.com/rubylouvre/archive/2010/12/29/1920358.html# var dom = { UID: 1, getAncestor: function (els) { var el, node, nodes = [], i = 0, ri = 0, uniqResult = {}; while (el = els[i++]) { node = el; do { pid = node.uniqueID || (node.uniqueID = dom.UID++); if (uniqResult[pid]) { break; } else if (node.nodeType === 9) { //如果能到达文档对象 uniqResult[el.uniqueID] = nodes[ri++] = el; } }while( node = node.parentNode); } return nodes; } }
相关文章:获取祖先元素