Подтвердить что ты не робот

Не удалось выполнить 'removeChild' в 'Node'

Я использую http://alexgorbatchev.com/SyntaxHighlighter/, чтобы выделить код на моем веб-сайте, но иногда в моем журнале я получаю ошибки Javascript следующим образом:

Uncaught NotFoundError: Не удалось выполнить 'removeChild' в 'Node': node, который будет удален, больше не является дочерним элементом этого node. Возможно, это было перемещено в обработчик события "размытие"?

Uncaught NotFoundError: Была сделана попытка ссылаться на node в контексте, где он не существует.

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

Может кто-нибудь помочь получить это исправление?

4b9b3361

Ответ 1

Мне пришлось иметь дело с одной и той же проблемой, и ответ путается и противоречит интуиции. Ну, он имеет свою логику, но ведет к нетривиальному поведению.

По существу, когда node удаляется из дерева 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);

Я предполагаю, что у вас есть функция detachEvent для удаления прослушивателей событий. Настройте код в соответствии с вашими потребностями.

В качестве альтернативы вы можете установить флаг (как свойство или атрибут или, лучше, облачную область) в текстовом поле в функции прослушивателя, и проверить его перед продолжением удаления node:

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

Вы также можете проверить, действительно ли textarea, если на самом деле это дочерний элемент node его parentNode, но такой тест настолько интуитивно понятен (по крайней мере мне), что я бы не рекомендовал это делать, опасаясь, что это поведение будет изменено в будущем.

Наконец, вы всегда можете положиться на оператор try...catch, но... ugh.

2016 Обновление

Естественно, использование такой структуры, как jQuery, сэкономит вам много работы с прослушивателями событий с помощью one, но эта функциональность придет к standard addEventListener:

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

Ответ 2

Я выхожу на конечность здесь и предполагаю, что некоторые из вас, которые находят этот вопрос, здесь, потому что вы googled ошибка, приведенная выше:

'removeChild' on 'Node': node, который нужно удалить, больше не является дочерним из этого node. Возможно, это было перемещено в обработчик события "размытие"?

Я использую 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;
    }
});

Я был бы очень удивлен, если бы не было лучшего решения, но, надеюсь, это поможет кому-то и, возможно, получит некоторые конструктивные комментарии.

Ответ 3

Хотя классический ответ на этот вопрос заключался в том, что это ошибка в коде JS, в React 16 существует серьезная ошибка, которая означает, что любой механизм браузера/расширения, модифицирующий DOM, ломает React.

Google Chrome, встроенный в функцию Переводчика, является наиболее распространенным преступником.

Проблема GitHub: https://github.com/facebook/react/issues/11538

Минимальный регистр: https://p93xxmr0rq.codesandbox.io/ (просто вручную щелкните правой кнопкой мыши "Перевести на" в Chrome и выберите из японского языка, затем нажмите кнопку)

Обходной путь: Как отключить Google Translate из HTML в Chrome

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

Ответ 4

Вместо textarea.parentNode.removeChild(textarea); Вы можете использовать textarea.parentNode.innerHTML = '' или что-то подобное, в зависимости от вашего контекста.

Ответ 5

Я нашел такое же сообщение об ошибке на простом jQuery script. Когда я попытался получить высоту элемента $('# element'). Height() Я увидел ту же ошибку на консоли.

Элемент существует и $('# element'). length равно 1.

Журнал элемента с console.log($ ('# element')) был похож на объект jQuery, но с большим количеством методов повторялся.

После многого отладки я обнаружил, что добавление обработчика события $(document).on(DOMContentLoaded DOMNodeInserted) сделало эту странную вещь объектами jQuery.

Надеюсь, что эта помощь поможет кому-то. Трудно найти.

Ответ 6

Я использую Time delay, и он работает для меня вот так.

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

Ответ 7

Я получал эту ошибку, и ничего выше не помогло мне, в конце концов я закончил с просто:

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

который отлично работает для меня.

Ответ 8

Попробуйте перевести свой сайт с помощью Google Chrome (щелкните правой кнопкой мыши на сайте и выберите "Перевести на английский". Если вы видите ошибку, возникающую в консоли, то вы знаете, что она вызвана Google Translate.

Связанная проблема GitHub: https://github.com/facebook/react/issues/11538.


Обходной путь от Дана Абрамова:

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

Отображать тексты в <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>

Подробное объяснение можно найти здесь: https://github.com/facebook/react/issues/11538#issuecomment-390386520

Ответ 9

вам нужно проверять каждый раз, когда выполняется метод, является ли элемент дочерним для данного родителя.

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

Ответ 10

Почему вы не используете jquery:

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