销毁使用Renderer2创建的元素的正确方法是什么?

时间:2017-06-09 19:45:59

标签: angular

在我们的代码库中,我们有一个虚拟重复指令,它使用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动态创建的节点的正确方法是什么?

2 个答案:

答案 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