无法在'Node'上执行'removeChild'

sco*_*sen 45 javascript

我正在使用http://alexgorbatchev.com/SyntaxHighlighter/突出显示我网站上的代码,但有时在我的日志中我会收到如下Javascript错误:

Uncaught NotFoundError:无法在'Node'上执行'removeChild':要删除的节点不再是此节点的子节点.也许它被移动到'模糊'事件处理程序中?

Uncaught NotFoundError:尝试在不存在的上下文中引用节点.

// set up handler for lost focus
attachEvent(textarea, 'blur', function(e)
{
   textarea.parentNode.removeChild(textarea);
   removeClass(highlighterDiv, 'source');
});
Run Code Online (Sandbox Code Playgroud)

这是attachEvent()函数代码:

function attachEvent(obj, type, func, scope)
{
    function handler(e)
    {
        e = e || window.event;

        if (!e.target)
        {
            e.target = e.srcElement;
            e.preventDefault = function()
            {
                this.returnValue = false;
            };
        }

        func.call(scope || window, e);
    };

    if (obj.attachEvent) 
    {
        obj.attachEvent('on' + type, handler);
    }
    else 
    {
        obj.addEventListener(type, handler, false);
    }
};
Run Code Online (Sandbox Code Playgroud)

有人可以帮忙解决这个问题吗?

Max*_*Art 55

我不得不处理同样的问题,答案是混乱和反直觉.嗯,它有其逻辑,但导致非平凡的行为.

实质上,当从DOM树中删除节点时,它会触发一个blur事件(focusout也在事件发生之前).

所以,当你打电话时removeChild,blur事件再次被触发,但这次textarea 仍然有它的parentNode定义,但textarea不再是它的父母的孩子了!(是的,请阅读两次.或者更多.)

目前这种情况发生在Chrome中,尽管Firefox已计划在相当长的一段时间内执行此操作.

作为解决方法,您可以删除附加的事件侦听器:

var onblur = function(e) {
    detachEvent(textarea, 'blur', onblur);
    textarea.parentNode.removeChild(textarea);
    removeClass(highlighterDiv, 'source');
};
attachEvent(textarea, 'blur', onblur);
Run Code Online (Sandbox Code Playgroud)

我假设你有一些detachEvent功能来删除事件监听器.根据您的需要调整代码.

或者,您可以在侦听器函数中的textarea上设置标志(如属性,属性或更好的范围变量),并在继续删除节点之前检查它:

var removed = false;
attachEvent(textarea, 'blur', function(e) {
    if (removed) return;
    removed = true;
    textarea.parentNode.removeChild(textarea);
    removeClass(highlighterDiv, 'source');
});
Run Code Online (Sandbox Code Playgroud)

你还可以在删除它之前检查它textarea是否真的是它的子节点parentNode,但是这样的测试是如此反直觉(至少对我而言)我不建议这样做,担心这种行为将来会改变.

最后,你总是可以依赖try...catch声明,但是......呃.

2016年更新

当然,使用像jQuery这样的框架可以为你节省大量附加事件监听器的工作one,但是这个功能也将成为标准addEventListener:

textarea.addEventListener('blur', handler, { once: true });
Run Code Online (Sandbox Code Playgroud)

  • 绝对使用`try ... catch`这样的垃圾. (5认同)

hyp*_*not 11

虽然这个问题的经典答案是它是JS代码中的一个错误,但是React 16存在一个主要错误,这意味着任何修改DOM的浏览器/扩展机制都会破坏React.

谷歌Chrome的内置翻译功能是最常见的罪魁祸首.

GitHub问题:https://github.com/facebook/react/issues/11538

最小的情况:https://p93xxmr0rq.codesandbox.io/(只需在Chrome中右键单击"翻译到",然后从日语中选择,然后单击按钮)

解决方法:如何在chrome中禁用来自html的google翻译

<meta name="google" content="notranslate">
Run Code Online (Sandbox Code Playgroud)


bil*_*oah 6

我在这里走出困境并假设有些发现这个问题的人在这里,因为你搜索了上面引用的错误:

'Node'上的'removeChild':要删除的节点不再是此节点的子节点.也许它被移动到'模糊'事件处理程序中?

我正在使用jQuery和DataTables 1.10.6,这个错误确实出现blur()在我更新单元格值的事件上.我的解决方案是在事件中添加一个条件,如下所示:

var blur = false;
$('table').on('blur', 'td select', function() {
    if (!blur) {
        blur = true;
        var cell = $(this).closest('td');
        table.cell(cell).data('example data');
        blur = false;
    }
});
Run Code Online (Sandbox Code Playgroud)

如果没有更好的解决方案,我会感到非常惊讶,但希望这可以帮助某人,也许可以获得一些建设性的评论.

  • @Fusion-我明白了,通常我不习惯在javascript标记问题上发布jQuery答案。然而,这篇文章的原因是我遇到了完全相同的错误**由于jQuery **和DataTables。是的,这不是专门解决问题,而是针对他在遇到此问题时提到的错误。由于这是我在Google上获得的最高搜索结果,因此有人到达这里并发现此答案有用的机会与其他任何人都一样。有时,为了给OP带来更多的人,我发布了答案。 (3认同)

Dáv*_*nár 6

尝试使用谷歌浏览器翻译您的网站(右键单击该网站并选择“翻译成英文”。如果您在控制台中看到错误发生,那么您就知道这是由谷歌翻译引起的。

相关 GitHub 问题:https : //github.com/facebook/react/issues/11538


Dan Abramov 的解决方法:

if (typeof Node === 'function' && Node.prototype) {
  const originalRemoveChild = Node.prototype.removeChild;
  Node.prototype.removeChild = function(child) {
    if (child.parentNode !== this) {
      if (console) {
        console.error('Cannot remove a child from a different parent', child, this);
      }
      return child;
    }
    return originalRemoveChild.apply(this, arguments);
  }

  const originalInsertBefore = Node.prototype.insertBefore;
  Node.prototype.insertBefore = function(newNode, referenceNode) {
    if (referenceNode && referenceNode.parentNode !== this) {
      if (console) {
        console.error('Cannot insert before a reference node from a different parent', referenceNode, this);
      }
      return newNode;
    }
    return originalInsertBefore.apply(this, arguments);
  }
}
Run Code Online (Sandbox Code Playgroud)

在呈现您的应用程序之前运行此代码。请记住,这会对性能造成轻微影响。


Shuhei Kagawa 的解决方法

<span>.

// Case 1
<div>
  {condition && 'Welcome'}
  <span>Something</span>
</div>

// A workaround for case 1
<div>
  {condition && <span>Welcome</span>}
  <span>Something</span>
</div>

// Case 2
<div>
  {condition && <span>Something</span>}
  Welcome
</div>

// A workaround for case 2
<div>
  {condition && <span>Something</span>}
  <span>Welcome</span>
</div>

Run Code Online (Sandbox Code Playgroud)

详细解释可以在这里找到:https : //github.com/facebook/react/issues/11538#issuecomment-390386520