Аннон, отличная работа. Я изменил оригинал плюс включенные модификации Стефана в следующем.
Кроме того, я убрал зависимость от Range, который преобразует функцию в общий алгоритм обхода между двумя узлами. Кроме того, я все обернул в одну функцию.
Мысли о других решениях:
- Не заинтересован в использовании jquery
- Использование cloneNode переводит результаты во фрагмент, что предотвращает многие операции, которые можно выполнить во время фильтрации.
- Использование querySelectAll на клонированном фрагменте является проблематичным, поскольку начальный или конечный узлы могут находиться в узле обтекания, следовательно, синтаксический анализатор может не иметь закрывающего тега?
Пример:
<div>
<p>A</p>
<div>
<p>B</p>
<div>
<p>C</p>
</div>
</div>
</div>
Предположим, что начальный узел - это абзац "A", а конечный узел - это абзац "C"
, Полученный клонированный фрагмент будет иметь вид:
<p>A</p>
<div>
<p>B</p>
<div>
<p>C</p>
а нам не хватает закрывающих тегов? в результате чего в фанки структуры DOM?
В любом случае, вот функция, которая включает опцию фильтра, которая должна возвращать ИСТИНА или ЛОЖЬ для включения / исключения из результатов.
var getNodesBetween = function(startNode, endNode, includeStartAndEnd, filter){
if (startNode == endNode && startNode.childNodes.length === 0) {
return [startNode];
};
var getNextNode = function(node, finalNode, skipChildren){
//if there are child nodes and we didn't come from a child node
if (finalNode == node) {
return null;
}
if (node.firstChild && !skipChildren) {
return node.firstChild;
}
if (!node.parentNode){
return null;
}
return node.nextSibling || getNextNode(node.parentNode, endNode, true);
};
var nodes = [];
if(includeStartAndEnd){
nodes.push(startNode);
}
while ((startNode = getNextNode(startNode, endNode)) && (startNode != endNode)){
if(filter){
if(filter(startNode)){
nodes.push(startNode);
}
} else {
nodes.push(startNode);
}
}
if(includeStartAndEnd){
nodes.push(endNode);
}
return nodes;
};