DOM4 compareDocumentPosition
我想实现compareDocumentPosition. Resig已经取得了great start at doing just this.我已经把他的代码整理好了
function compareDocumentPosition(other) { var ret = 0; if (this.contains) { if (this !== other && this.contains(other)) { ret += 16; } if (this !== other && other.contains(this)) { ret += 8; } if (this.sourceIndex >= 0 && other.sourceIndex >= 0) { if (this.sourceIndex < other.sourceIndex) { ret += 4; } if (this.sourceIndex > other.sourceIndex) { ret += 2; } } else { ret += 1; } } return ret; }
这适用于Element,但不适用于Text或DocumentFragment.这是因为IE8不会在这些节点上提供.sourceIndex. (它不会给.contains,但我已经解决了这个问题)
如何有效地写入对应于DOCUMENT_POSITION_FOLLOWING和DOCUMENT_POSITION_PRECEDING的= 4和= 2位.
为了额外的参考,这两个是由DOM4定义的树顺序定义的
An object A is preceding an object B if A and B are in the same tree and A comes before B in tree order.
An object A is following an object B if A and B are in the same tree and A comes after B in tree order.
The tree order is preorder,depth-first traversal.
大多数现代浏览器都实现了这一点(包括IE9).所以你只需要在IE8中运行的东西(我不关心IE6 / 7,但它是否真的很棒!)
解决方法
function recursivelyWalk(nodes,cb) { for (var i = 0,len = nodes.length; i < len; i++) { var node = nodes[i]; var ret = cb(node); if (ret) { return ret; } if (node.childNodes && node.childNodes.length) { var ret = recursivelyWalk(node.childNodes,cb); if (ret) { return ret; } } } } function testNodeForComparePosition(node,other) { if (node === other) { return true; } } function compareDocumentPosition(other) { function identifyWhichIsFirst(node) { if (node === other) { return "other"; } else if (node === reference) { return "reference"; } } var reference = this,referenceTop = this,otherTop = other; if (this === other) { return 0; } while (referenceTop.parentNode) { referenceTop = referenceTop.parentNode; } while (otherTop.parentNode) { otherTop = otherTop.parentNode; } if (referenceTop !== otherTop) { return Node.DOCUMENT_POSITION_DISCONNECTED; } var children = reference.childNodes; var ret = recursivelyWalk( children,testNodeForComparePosition.bind(null,other) ); if (ret) { return Node.DOCUMENT_POSITION_CONTAINED_BY + Node.DOCUMENT_POSITION_FOLLOWING; } var children = other.childNodes; var ret = recursivelyWalk( children,reference) ); if (ret) { return Node.DOCUMENT_POSITION_CONTAINS + Node.DOCUMENT_POSITION_PRECEDING; } var ret = recursivelyWalk( [referenceTop],identifyWhichIsFirst ); if (ret === "other") { return Node.DOCUMENT_POSITION_PRECEDING; } else { return Node.DOCUMENT_POSITION_FOLLOWING; } }