【问题标题】:Failed to execute 'removeChild' on 'Node'无法在“节点”上执行“removeChild”
【发布时间】:2014-03-22 11:23:51
【问题描述】:

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

未捕获的 NotFoundError:无法在“节点”上执行“removeChild”:要删除的节点不再是该节点的子节点。也许它是在“模糊”事件处理程序中移动的?

未捕获的 NotFoundError:尝试在不存在的上下文中引用节点。

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

这里是 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);
    }
};

谁能帮忙解决这个问题?

【问题讨论】:

  • 什么是 textarea html ?如果可能的话,做一个小提琴。
  • textarea = document.createElement('textarea') 你可以在完整的源代码中看到它。你可以试试这个演示 netkoder.dk/netkoder/eksempler/eksempel0009.html 但错误不会正常发生。我有时只会在记录 javascript 错误的网站日志中收到错误消息。
  • attachEvent?那是从哪里来的?抱歉,不想费力地翻阅 4 个脚本文件来找到它。
  • 它在上面链接的同一个文件中。
  • 也许这是在尝试删除节点之前测试节点是否存在的解决方案,有人可以确认这会使错误消息消失吗? : if (textarea.parentNode) { textarea.parentNode.removeChild(textarea); }

标签: javascript


【解决方案1】:

我不得不处理同样的问题,而答案令人困惑且违反直觉。嗯,它有它的逻辑,但会导致不平凡的行为。

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

所以,当您调用removeChild 时,blur 事件会再次触发,但这一次textarea 仍然 定义了parentNode,但是textarea 不再是其父母的孩子! (是的,读两遍。或者更多。)

虽然 Firefox 使用 planned to do the same 已经有一段时间了,但目前 Chrome 会出现这种情况。

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

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

我假设您有一些 detachEvent 函数来删除事件侦听器。根据您的需要调整代码。

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

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

您还可以在删除之前检查 textarea 是否实际上是其 parentNode 的子节点,但是这样的测试非常违反直觉(至少对我而言),我不建议这样做,因为害怕将来会改变这种行为。

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

2016 年更新

当然,使用 jQuery 之类的框架可以为您节省大量使用 one 附加事件侦听器的工作,但此功能也将出现在 standard addEventListener 中:

textarea.addEventListener('blur', handler, { once: true });

【讨论】:

  • 谢谢。我不明白,但你知道如何更改代码以避免错误吗?
  • @scootergrisen 是的,我编辑了我的答案以包含几个解决方案。
  • 绝对使用try...catch 来处理这种废话。
  • 救了我的命,已经调试了两个小时了!不知道触发了模糊...
  • @OCDev 我理解这种感觉,但从语义上讲,try...catch 应该用于我们不想破坏代码的不可预测的行为(或者说,用于特征检测)。听起来可能很奇怪,但这实际上是一个记录在案的标准案例。
【解决方案2】:

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

谷歌浏览器内置的翻译功能是最常见的罪魁祸首。

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

最小大小写:https://p93xxmr0rq.codesandbox.io/(只需在 Chrome 中手动右键单击“翻译为”并从日语中选择然后单击按钮)

解决方法:How to disable google translate from html in chrome

<meta name="google" content="notranslate">

【讨论】:

  • 我尝试了很多解决方案,最后在阅读了您的评论后,我禁用了谷歌自动翻译。现在错误消失了,不再对崩溃做出反应。谢谢。
  • 从用户体验的角度来看,禁用谷歌翻译可能不是您应用的最佳解决方案。然而,从 DX 的角度来看,这是一个很好的解决方案。除了完全禁用谷歌翻译之外,还有一个解决方法github.com/facebook/react/issues/11538#issuecomment-390386520
【解决方案3】:

我在这里冒着风险,假设你们中的一些人在这里找到了这个问题,因为你用谷歌搜索了上面引用的错误:

'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;
    }
});

如果没有更好的解决方案,我会感到非常惊讶,但希望这对某人有所帮助,并可能获得一些建设性的 cmets。

【讨论】:

  • @Fusion - 我明白了,通常我没有在 javascript 标记问题上发布 jQuery 答案的习惯。然而,这篇文章的原因是我遇到了完全相同的错误因为 jQuery 和 DataTables。诚然,这并没有具体解决这个问题,但我正在解决他在我遇到的上下文中提到的错误。由于这是我发现的最高谷歌结果,因此有人到达这里并发现此答案有用的机会与任何人一样好。有时我会为了更多的人而发布答案。
  • 叮!你就是这样做的!
  • 只想在此处更新答案,因为其中有错误。在您的事件处理函数中,您将模糊设置为 true,然后设置为 false。这行不通,您只需在最后将 blur 设置为 true,如下所示:` $('table').on('blur', 'td select', function() { if (!blur) { var cell = $(this).closest('td'); table.cell(cell).data('example data'); blur = true; } });`
  • @jjsquared - 没有。
  • 我如何在 cmets 中格式化代码,即使有 3 个反引号也不让我这样做
【解决方案4】:

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

相关 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);
  }
}

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


Shuhei Kagawa 的解决方法

&lt;span&gt; 中呈现文本。

// 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>

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

【讨论】:

  • 这是一个救生员。从来没有想过这可能是原因。
  • 很难说,对于大多数应用程序来说这无关紧要。您必须测试并查看。
  • 我怀疑这段代码是否能完成这项工作,确实如此。
【解决方案5】:

我使用时间延迟,它对我来说就像这样。

// 设置失去焦点的处理程序 附加事件(文本区域,“模糊”,函数(e) { 设置超时(函数(){ textarea.parentNode.removeChild(textarea); removeClass(highlighterDiv, 'source'); }, 0); });

【讨论】:

  • 不错!这对我来说是最简单、最直观的解决方案。
【解决方案6】:

您可以使用textarea.parentNode.innerHTML = '' 或类似的东西来代替textarea.parentNode.removeChild(textarea);,具体取决于您的上下文。

【讨论】:

    【解决方案7】:

    我遇到了这个错误,上面没有任何帮助,最终我得到了简单的结果:

    if (img.parentNode) {
        body.removeChild(img);
    }
    

    这对我来说非常适合。

    【讨论】:

      【解决方案8】:

      我在一个简单的 jQuery 脚本中发现了相同的错误消息。 当我尝试获取元素 $('#element').height() 的高度时,我在控制台上看到了同样的错误。

      元素存在且 $('#element').length 为 1。

      带有console.log( $('#element') ) 的元素的日志就像一个jQuery对象,但有很多方法重复。

      经过大量调试后,我发现添加 $(document).on('DOMContentLoaded DOMNodeInserted') 事件处理程序会使 jQuery 对象变得奇怪。

      希望这对某人有所帮助,因为它很难找到。

      【讨论】:

        【解决方案9】:

        从程序触发的事件类型可能与 Dom 的默认操作不同。如果您检查类型,并使用 if (type === 'typeYouWant') 作为保护子句,您可能会跳过不需要的代码执行。控制台记录事件以检查是否有可以隔离的“类型”。

           formEditEl.addEventListener('blur', this._cancelEdit.bind(this));
        
          _cancelEdit(e) {
            if (e.type === "change") document.querySelector('.form__edit').remove();
            };
        

        【讨论】:

          【解决方案10】:

          您需要在每次执行该方法时检查该元素是否是给定父元素的子元素。

          if(box.parentElement === parentBox) {
              parentBox.removeChild(box);
          }
          

          【讨论】:

            【解决方案11】:

            为什么不使用 jquery:

            $("#element_id").remove();
            

            【讨论】:

            • 因为没有人需要使用 jquery
            猜你喜欢
            • 1970-01-01
            • 2020-07-17
            • 2018-06-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-26
            • 2022-11-12
            相关资源
            最近更新 更多