Javascript DOM ChildNodes属性不会捕获所有子项

时间:2014-07-04 15:16:49

标签: javascript html dom

我想保存一个DOM子树(div下的所有内容,名为"框图")然后将它绘制在名为" bus_diagram"的div上。保存childNodes属性似乎不会出于某种原因捕获所有元素。

这是我正在使用的javascript。在调用函数" dostuff()" " block_diagram"应该去" bus_diagram"

var SAVED_BLOCK_DOM = null;

function save_block() {
    SAVED_BLOCK_DOM = document.getElementById("block_diagram").childNodes;
}

function refresh_block() {
    for (var i = 0; i < SAVED_BLOCK_DOM.length; i++) {
        document.getElementById("bus_diagram").appendChild(SAVED_BLOCK_DOM[i]);
    }
}

function dostuff() {
    save_block();
    refresh_block();
}

这是一个JSFiddle:http://jsfiddle.net/BFp5s/3/

1 个答案:

答案 0 :(得分:1)

.childNodes是节点的实时集合,当您开始在节点上执行.appendChild()时(将元素移动到DOM中的不同位置),实时集合会在您迭代时更改,导致您错过节点。因此,当您的for循环的索引为0时,您会在列表的.appendChild()元素上执行0th。这会从实时列表中删除该元素。然后,您将索引增加到1,但下一个要处理的项目现在位于列表中的0th位置,导致您处理其他所有项目。

您可以将实时列表的副本复制到一个数组中(因此在迭代时不会更改)或更改迭代列表的方式。

例如,您可以将save_block()更改为:

function save_block() {
    SAVED_BLOCK_DOM = Array.prototype.slice.call(document.getElementById("block_diagram").childNodes, 0);
}

这会使SAVED_BLOCK_DOM成为正常数组,因此在迭代时它不会改变。

jsFiddle演示:http://jsfiddle.net/jfriend00/R8c94/


或者,如果您需要/需要支持IE6 / 7/8支持,这对于上述复制机制不起作用,您可以手动复制nodeList:

function save_block() {
    SAVED_BLOCK_DOM = [];
    var list = document.getElementById("block_diagram").childNodes;
    for (var i = 0; i < list.length; i++) {
        SAVED_BLOCK_DOM.push(list[i]);
    }
}

如果您不需要SAVED_BLOCK_DOM继续保留节点列表并希望支持IE8,您可以像这样更改迭代方式:

function refresh_block() {
    while (SAVED_BLOCK_DOM.length) {
        document.getElementById("bus_diagram").appendChild(SAVED_BLOCK_DOM[0]);
    }
}

jsFiddle演示:http://jsfiddle.net/jfriend00/PK7Tg/