8

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

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 也都存在。

我觉得这不合逻辑,因为元素根据定义是其父节点的子节点。也许 StackOverflow 可以帮助我,在这里?

4

3 回答 3

8

来自mdn 文档

如果 child 实际上不是元素节点的子节点,则该方法将引发异常。如果在调用时 child 实际上是 element 的子项,但在尝试删除元素的过程中被调用的事件处理程序删除(例如,模糊),也会发生这种情况。

我可以在jsfiddle中重现此错误

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

于 2012-07-22T12:50:31.347 回答
2

如果您尝试在 onblur 处理程序中修改您尝试在另一个处理程序中删除的同一节点(例如 onfocus、keydown 等),那么第一次调用removeChild将在实际删除节点之前触发 onblur 处理程序。如果 onblur 处理程序随后修改节点以使其父节点发生更改,则控制将从 onblur 处理程序返回到removeChildonfocus 处理程序中的调用,然后该处理程序将尝试删除节点并失败并出现您描述的异常。

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

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

以下代码将显示 onblur 事件处理程序removeChild在 onfocus 实际移除子项之前如何运行。它也在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 
于 2012-11-18T00:21:32.573 回答
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
};
于 2012-07-22T12:48:54.807 回答