簡體   English   中英

DOM樹遍歷

[英]DOM tree traversal

我最近面試了 Facebook 的前端工程師職位。 對於我的手機屏幕,我提出了以下問題:給定 DOM 樹中的一個節點,從相同的 DOM 樹中找到相同位置的節點。 為清楚起見,請參見下圖。

 A         B

 O        O
 |\       |\
 O O      O O
  /|\      /|\
 O O O    O O O
      \        \
       O        O

這是我的解決方案,我想知道我可以做些什么來改進/優化它。

var rootA, rootB;

function findNodeB(nodeA) {
    // Variable to store path up the DOM tree
    var travelPath = [];

    // Method to travel up the DOM tree and store path to exact node
    var establishPath = function(travelNode) {
        // If we have reached the top level node we want to return
        // otherwise we travel up another level on the tree
        if (travelNode === rootA) {
            return;
        } else {
            establishPath(travelNode.parentNode);
        }

        // We store the index of current child in our path
        var index = travelNode.parentNode.childNodes.indexOf(travelNode);
        travelPath.push(index);     
    }

    var traverseTree = function(bTreeNode, path) {
        if(path.length === 0) {
            return bTreeNode;
        } else {
            traverseTree(bTreeNode.childNodes[path.pop()], path);
        }
    }

    establishPath(rootB, nodeA);

    return traverseTree(rootB, travelPath);
}           

由於至少 Axel 對迭代解決方案表現出興趣,因此它是:

給定具有相同結構的兩棵樹,以及第一棵樹中的一個指定節點,在第二棵樹中定位具有相同位置的節點。

如果我們沒有關於兩棵樹的其他信息,那么每個節點的位置可以表征為從根節點開始的路徑,其中路徑中的每一步都被指定為 childNode 數組的索引。

function indexOf(arrLike, target) {
    return Array.prototype.indexOf.call(arrLike, target);
}

// Given a node and a tree, extract the nodes path 
function getPath(root, target) {
    var current = target;
    var path = [];
    while(current !== root) {
        path.unshift(indexOf(current.parentNode.childNodes, current));
        current = current.parentNode;
    }
    return path;
}

// Given a tree and a path, let's locate a node
function locateNodeFromPath(root, path) {
    var current = root;
    for(var i = 0, len = path.length; i < len; i++) {
        current = current.childNodes[path[i]];
    }
    return current;
}

function getDoppleganger(rootA, rootB, target) {
    return locateNodeFromPath(rootB, getPath(rootA, target));
}

編輯:正如 Blue Skies 所觀察到的,childNodes 沒有 .indexOf()。 使用 Array.prototype.indexOf.call() 更新

這是並行遍歷解決方案

function findDomNodeInTree(rootA, rootB, targetNode) {
    if (rootA === targetNode){
        return rootB;
    }

    let nodeB = null;

    for (let i=0; i<rootA.childNodes.length && nodeB === null; i++){
        nodeB = findDomNodeInTree(rootA.childNodes[i], rootB.childNodes[i], targetNode);
    }

    return nodeB;
}

它的時間復雜度是 O(N),在最壞的情況下,我們需要遍歷整棵樹。

我不認為它比首先找到路徑的解決方案效率低。 在每個級別都有一個對indexOf的調用,它可能需要遍歷該級別上的所有節點才能找到索引。

您可以使用Array.from (在 ES6 中標准化)而不是Array.prototype.indexOf.call

Array.from(travelNode.parentNode.childNodes).indexOf(travelNode);

我會並行遍歷兩棵樹,當我到達 treeA 中的節點時,返回並行節點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM