Cross Browser сравнить положение документа
-
26-10-2019 - |
Вопрос
Я хочу реализовать сравнение. RESIG сделал Отличное начало в том, чтобы сделать только это. Анкет Я взял его код и украсил его
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
Либо, но я уже исправил эту проблему)
Как эффективно написать +=4
а также +=2
бит, который соответствует Document_position_following а также Document_position_preceding.
Для дополнительной ссылки эти два определены по порядку дерева, который Dom4 определяет как
Объект A предшествует объекту B, если A и B находятся в том же дереве, а A приходит до B в порядке дерева.
Объект A следует за объектом B, если A и B находятся в том же дереве, а A приходит после B в порядке дерева.
Порядок дерева-предварительный заказ, первая глубина.
Большинство современных браузеров реализуют это (включая 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,
testNodeForComparePosition.bind(null, 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;
}
}
Я написал это сам. Я думал, что эта реализация была ошибкой, но это была ошибка в каком -то другом моем коде. Кажется довольно солидным.
Другие советы
Ответ от Raynos - верхний старт, но не запускается из коробки. Node.*
не может быть найден и .bind
недоступен в IE8.
Вот код, готовый к использованию в Internet Explorer 8:
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;
}
}
var DOCUMENT_POSITION_DISCONNECTED = 1;
var DOCUMENT_POSITION_PRECEDING = 2;
var DOCUMENT_POSITION_FOLLOWING = 4;
var DOCUMENT_POSITION_CONTAINS = 8;
var DOCUMENT_POSITION_CONTAINED_BY = 16;
function compareDocumentPosition(thisNode, other) {
function identifyWhichIsFirst(node) {
if (node === other) {
return "other";
} else if (node === reference) {
return "reference";
}
}
var reference = thisNode,
referenceTop = thisNode,
otherTop = other;
if (this === other) {
return 0;
}
while (referenceTop.parentNode) {
referenceTop = referenceTop.parentNode;
}
while (otherTop.parentNode) {
otherTop = otherTop.parentNode;
}
if (referenceTop !== otherTop) {
return DOCUMENT_POSITION_DISCONNECTED;
}
var children = reference.childNodes;
var ret = recursivelyWalk(
children,
function(p) {
(function() {
var localOther = other;
return testNodeForComparePosition(localOther, p);
})();
}
);
if (ret) {
return DOCUMENT_POSITION_CONTAINED_BY +
DOCUMENT_POSITION_FOLLOWING;
}
var children = other.childNodes;
var ret = recursivelyWalk(
children,
function(p) {
(function() {
var localOther = reference;
return testNodeForComparePosition(localOther, p);
})();
}
);
if (ret) {
return DOCUMENT_POSITION_CONTAINS +
DOCUMENT_POSITION_PRECEDING;
}
var ret = recursivelyWalk(
[referenceTop],
identifyWhichIsFirst
);
if (ret === "other") {
return DOCUMENT_POSITION_PRECEDING;
} else {
return DOCUMENT_POSITION_FOLLOWING;
}
}
Вы называете это так:
compareDocumentPosition(sourceElement, elementToTest)
(Это как звонить sourceElement.compareDocumentPosition(elementToTest)
)