通过parentNode.removeChild删除元素会引发DOM异常8

时间:2012-07-22 12:27:34

标签: javascript dom removechild domexception

我的代码大致如下(我删除了一些部分,因为它们无关紧要):

Library.focus = function(event) {
    var element, paragraph;

    element = event.srcElement;

    paragraph = document.createElement("p");
    paragraph.innerText = element.innerText;

    element.parentNode.insertBefore(paragraph, element);        // Line #1
    element.parentNode.removeChild(element);                    // Line #2
};

我遇到的问题是,我编号为第2行的最后一个电话会抛出这个:

Uncaught Error: NOT_FOUND_ERR: DOM Exception 8

请注意,前一行#1工作正常,并在其前插入段落节点。 Element是一个现有元素,element.parentNode和element.parentNode.removeChild也都存在。

我发现这不合逻辑,因为元素根据定义是其parentNode的子元素。 也许StackOverflow能够在这里帮助我吗?

3 个答案:

答案 0 :(得分:8)

来自mdn docs

  

如果child实际上不是元素节点的子节点,则该方法   抛出一个例外。如果孩子实际上是一个,也会发生这种情况   呼叫时元素的子节点,但被事件删除   在尝试删除元素的过程中调用的处理程序(例如,   模糊。)

我可以在jsfiddle

中重现此错误

基本上,你聚焦元素,触发一个删除,触发模糊,移动元素,使元素不再是父元素。

答案 1 :(得分:2)

如果您尝试在onblur处理程序中修改您尝试在另一个处理程序中删除的同一节点(例如onfocus,keydown等),则第一次调用removeChild将触发onb​​lur处理程序在实际删除节点之前。 如果onblur处理程序然后修改节点以使其父节点发生更改,则控件将从onblur处理程序返回到onfocus处理程序中的removeChild调用,然后该函数将尝试删除节点并因您描述的异常而失败。 / p>

在你的onfocus处理程序中调用removeChild之前检查孩子是否存在的任何数量都是徒劳的,因为这些检查将在触发onb​​lur处理程序之前发生。

除了重新安排事件处理和节点修​​改之外,最好的办法是在try catch块中处理异常。

以下代码将显示onflur事件处理程序如何在onfocus中removeChild实际删除子项之前运行。它也在jsfiddle

HTML

<div id="iParent">
    <input id="i">
</div>

JS

var input = document.querySelector("#i"),
inputParent = document.querySelector('#iParent');

input.onblur = function() {
    console.log('onblur : input ' + (input.parentNode ? 'has' : 'doesnt have') 
            + ' a parent BEFORE delete');
    try {
        inputParent.removeChild(input);
    } catch (err) {
        console.log('onblur : removeChild failed, input ' 
                + (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
        return false;
    }
    console.log('onblur : child removed');
};

input.onfocus = function() {
    console.log('onfocus : input ' + (input.parentNode ? 'has' : 'doesnt have') 
            + ' a parent BEFORE delete');
    try {
        inputParent.removeChild(input);
    } catch (err) {
        console.log('onfocus : removeChild failed, input ' 
                + (input.parentNode ? 'has' : 'doesnt have') + ' a parent');
        return false;
    }
    console.log('onfocus : child removed');
};​

关注输入字段后的控制台输出将是

onfocus : input has a parent BEFORE delete
onblur : input has a parent BEFORE delete
onblur : child removed
onfocus : removeChild failed, input doesnt have a parent 

答案 2 :(得分:0)

不要将事件作为Library.focus函数的参数传递。它会起作用。

Library.focus = function() {
    var element, paragraph;

    element = event.srcElement;

    paragraph = document.createElement("p");
    paragraph.innerText = element.innerText;

    element.parentNode.insertBefore(paragraph, element);        // Line #1
    element.parentNode.removeChild(element);                    // Line #2
};