Не удалось выполнить '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);
}
};
Может кто-нибудь помочь получить это исправление?
Ответы
Ответ 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();