操作DOM后,元素不会在路由器导航中被破坏

elc*_*nrs 8 angular

我有一个指令,需要将应用它的元素移动到文档的主体:

@Directive({
  selector: '[myDirective]'
})
export class MyDirective implements AfterViewInit {
  constructor(private elem: ElementRef,
    private renderer: Renderer2) {
  }

  ngAfterViewInit() {
    // Move element to body
    this.renderer.appendChild(document.body, this.elem.nativeElement);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我在一个元素中使用这个指令ngIf,我根据一些条件进行切换:

<div myDirective *ngIf="visible">Test</div>
<button (click)="visible = !visible">Toggle</button>
Run Code Online (Sandbox Code Playgroud)

当它运行时,div将按预期显示按钮之后,因为它被附加到正文.此时切换按钮仍然有效,我可以显示/隐藏div.

当我介绍路线时,问题出现了:

<a routerLink="/route/1">Link</a>
<div myDirective *ngIf="visible">Test</div>
<button (click)="visible = !visible">Toggle</button>
Run Code Online (Sandbox Code Playgroud)

现在,如果我显示div,并导航到另一条路线,div应该被摧毁,但它仍然可见!如果我不将div移动到身体,那么它的行为与预期的一样.

首先,我尝试删除元素,ngOnDestroy但这不适用于动画,因为它删除元素而不播放它:离开动画.

我目前的解决方法是将路由器注入指令并订阅第一个将div恢复到其原始容器的事件:

this.routerSubscription = router.events.first().subscribe(() => {
  this.renderer.appendChild(this.parentNode, this.elem.nativeElement);
});
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但它并不好,因为现在该指令在路由器中具有依赖性,而它应该对它一无所知.

如何改进这个黑客以确保元素被正确销毁?

演示: https ://stackblitz.com/edit/angular-qximjw?file = app%2Fapp.component.ts

要重现此问题:

  1. 确保它位于根目录而不是路由中的URL
  2. 单击切换按钮
  3. 单击链接以导航到路线
  4. 观看div不会消失

Pen*_*gyy 3

您可以添加代码来删除元素ngOnDestroy

ngOnDestroy() {
  if (this.routerSubscription) {
    this.routerSubscription.unsubscribe();
  }
  document.body.removeChild(this.elem.nativeElement);
}
Run Code Online (Sandbox Code Playgroud)

但请注意,当您导航到同一路线时,角度不会破坏它(这意味着 ngOnDestroy 不会触发)。您可以尝试添加另一条路线并导航至该路线进行确认。

请参阅演示