在我们的代码库中,我们有一个虚拟重复指令,它使用Renderer2来创建这样的div:
this.renderer2.createElement('div');
在ngOnDestroy方法中,我们正在破坏它:
this.renderer.destroyNode(this.offsetBeforeEl);
这很好用,我们没有问题,直到我们在prod模式下构建应用程序并且我们开始收到以下错误:
main.js?d73b003…:formatted:87193 Uncaught (in promise) TypeError: this.renderer.destroyNode is not a function
我在该行添加了一个断点,发现实际上destroyNode不是Renderer2上的方法。我转到了angular的源代码,并在抽象类定义中找到了方法上面的注释:
/**
* This property is allowed to be null / undefined,
* in which case the view engine won't call it.
* This is used as a performance optimization for production mode.
*/
destroyNode: ((node: any) => void)|null;
所以我检查了视图的代码并看到了:
if (view.renderer.destroyNode) {
destroyViewNodes(view);
}
if (isComponentView(view)) {
view.renderer.destroy();
}
如果我不能依赖此方法,那么破坏使用Renderer2动态创建的节点的正确方法是什么?
答案 0 :(得分:5)
使用renderer.removeChild
方法。
直到我们在prod模式下构建应用程序
destroyNode
方法在DebugRenderer2上定义,该方法未在生产模式中使用。
处理节点删除的正确方法可以从angular的方式推断出来,例如execRenderNodeAction函数:
function execRenderNodeAction(
view: ViewData, renderNode: any, action: RenderNodeAction, parentNode: any, nextSibling: any,
target?: any[]) {
const renderer = view.renderer;
switch (action) {
case RenderNodeAction.RemoveChild:
renderer.removeChild(parentNode, renderNode);
break;
所以,请像这样使用removeChild
:
const parent = this.renderer.createElement('div');
const child = this.renderer.createElement('span');
this.renderer.appendChild(parent, child);
// using remove child
this.renderer.removeChild(parent, child);
答案 1 :(得分:3)
要删除所有子项,您必须遍历子项元素。
请注意,children
不是真正的数组,因此必须首先进行转换。
Array.from(this.elementRef.nativeElement.children).forEach(child => {
console.log('children.length=' + this.elementRef.nativeElement.children.length);
this.renderer.removeChild(this.elementRef.nativeElement, child);
});
日志记录语句表明实际上并没有从DOM中“实时”删除子级-这就是为什么while循环无法删除lastChild
的原因。
如果这些元素不是您最初添加的,请格外小心-因为如果它们是组件,则可能会导致内存泄漏或各种怪异现象。上面仅测试了将自己添加到空元素节点中的元素。
我以为我应该可以做[...this.elementRef.nativeElement.children]
,但是这抱怨slice
不存在-所以我只是恢复为Array.from
。