我如何递归DOM树?

sma*_*irt 2 recursion jquery dom

所以我有一系列嵌套的ul元素作为树的一部分,如下所示:

<ul>
<li>
    <ul>
        <li>1.1</li>
        <li>1.2</li>
    </ul>
    <ul>
        <li>2.1</li>
        <li>
            <ul>
                <li>2.2</li>
            </ul>
        </li>
    </ul>
    <ul>
        <li>3.1</li>
        <li>3.2</li>
    </ul>
</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

假设3.1是所选节点,当用户点击之前,所选节点应为2.2.坏消息是可能存在任何数量的层次.如何使用jquery找到与当前所选节点相关的上一个节点(li)?

Anu*_*rag 5

DOM定义了文档遍历类,允许顺序处理树内容.TreeWalker和NodeIterator类是完美的候选者.

首先,我们创建一个可以顺序遍历<li>节点的TreeWalker实例.

var walker = document.createTreeWalker(
    document.body, 
    NodeFilter.SHOW_ELEMENT,
    function(node) {
            var hasNoElements = node.getElementsByTagName('*').length == 0;
            return (node.nodeName == "LI" && hasNoElements) ? 
                        NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    },
    false
);
Run Code Online (Sandbox Code Playgroud)

接下来,我们迭代到TreeWalker中的当前节点.假设我们有一个对当前节点的引用myNode.我们将遍历此walker,直到达到myNode或为null值.

while(walker.nextNode() != myNode && walker.currentNode);
Run Code Online (Sandbox Code Playgroud)

到达这个TreeWalker中的节点后,获取前一个节点是件小事.

var previousNode = walker.previousNode();
Run Code Online (Sandbox Code Playgroud)

你可以在这里试试一个例子.


这是向后树步行者的通用版本.它是TreeWalker界面的一个小包装器.

function backwardsIterator(startingNode, nodeFilter) {
    var walker = document.createTreeWalker(
        document.body, 
        NodeFilter.SHOW_ELEMENT,
        function(node) {
            return nodeFilter(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
        },
        false
    );

    walker.currentNode = startingNode;

    return walker;
}
Run Code Online (Sandbox Code Playgroud)

它需要一个起始节点和一个自定义过滤器功能来删除不需要的元素.以下是从给定节点开始并仅包含叶li元素的示例用法.

var startNode = document.getElementById("2.1.1");

// creates a backwards iterator with a given start node, and a function to filter out unwanted elements.
var iterator = backwardsIterator(startNode, function(node) {
    var hasNoChildElements = node.childElementCount == 0;
    var isListItemNode = node.nodeName == "LI";

    return isListItemNode && hasNoChildElements;
});

// Call previousNode() on the iterator to walk backwards by one node.
// Can keep calling previousNode() to keep iterating backwards until the beginning.
iterator.previousNode()
Run Code Online (Sandbox Code Playgroud)

更新了交互式示例.点击列表项以突出显示上一个列表项.