Angular 5动画:如何使用:从DOM中删除组件时保留过渡

Angular 5动画:如何使用:从DOM中删除组件时保留过渡,angular,angular-animations,Angular,Angular Animations,我们在项目中使用@ng bootstrap/ng bootstrap库来实现一些行为/组件,如Modal。最近,我想消除这种依赖性,并用Angular实现引导模式行为。其实很简单。让我简单地告诉你它是如何工作的: 我有一个模态服务和模态组件。服务通过ComponentFactoryResolver(可以查看详细信息)和外接程序DOM动态创建模式组件。通过关闭modal,modal只调用从服务中定义的回调函数,这只会破坏组件,从DOM中删除 所以:对于这个模态组件,我有两个动画状态,输入和离开。进

我们在项目中使用@ng bootstrap/ng bootstrap库来实现一些行为/组件,如Modal。最近,我想消除这种依赖性,并用Angular实现引导模式行为。其实很简单。让我简单地告诉你它是如何工作的:

我有一个模态服务和模态组件。服务通过ComponentFactoryResolver(可以查看详细信息)和外接程序DOM动态创建模式组件。通过关闭modal,modal只调用从服务中定义的回调函数,这只会破坏组件,从DOM中删除

所以:对于这个模态组件,我有两个动画状态,输入和离开。进入很有效。组件一出现在dom中,就会触发预定义的:enter状态,我的动画就会工作。但是:离开并不重要

这正是关闭模式的工作原理:打开模式时,单击关闭按钮或模式背景上的任何其他位置。这只是调用close函数,该函数定义为输入,在创建过程中由服务提供

@Input() closeCallback: Function;
服务只是从DOM中删除组件

由于组件在单击“关闭”按钮后立即移除,因此动画没有我认为需要的时间。所以:离开不起作用。

我本想在close上设置一个超时(延迟),并手动触发动画,但由于我想使用预定义的行为:enter和:leave,我无法理解这是如何实现的。那么,我该如何让我的动画工作呢?(带或不带:请假)

服务代码:

@Injectable()
export class ModalService implements OnDestroy {

  private renderer: Renderer2;
  private componentRef: ComponentRef<ModalComponent>;

  constructor(private rendererFactory: RendererFactory2,
              private componentFactoryResolver: ComponentFactoryResolver,
              private appRef: ApplicationRef,
              private injector: Injector) {
    this.renderer = rendererFactory.createRenderer(null, null);
  }

  ngOnDestroy() {
    this.componentRef.destroy();
  }

  open(content: string, titel: string, primaryButtonLabel: string, secondaryButtonLabel?: string, primaryButtonCallback?: Function, secondaryButtonCallback?: Function) {
    // 1. Create a component reference from the component
    this.componentRef = this.componentFactoryResolver
      .resolveComponentFactory(ModalComponent)
      .create(this.injector);

    this.componentRef.instance.content = content;
    this.componentRef.instance.titel = titel;
    this.componentRef.instance.primaryButtonLabel = primaryButtonLabel;
    this.componentRef.instance.secondaryButtonLabel = secondaryButtonLabel;
    this.componentRef.instance.primaryButtonCallback = primaryButtonCallback;
    this.componentRef.instance.secondaryButtonCallback = secondaryButtonCallback;
    this.componentRef.instance.closeCallback = (() => {
      this.close();
    });

    // 2. Attach component to the appRef so that it's inside the ng component tree
    this.appRef.attachView(this.componentRef.hostView);

    // 3. Get DOM element from component
    const domElem = (this.componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;

    // 4. Append DOM element to the body
    this.renderer.appendChild(document.body, domElem);
    this.renderer.addClass(document.body, 'modal-open');
  }

  close() {
    this.renderer.removeClass(document.body, 'modal-open');
    this.appRef.detachView(this.componentRef.hostView);
    this.componentRef.destroy();
  }
}
模态HTML不是很相关,但您可以想象如下:

<div [@modalSlideInOut] role="document" class="modal-dialog">
  <div ....
      <button (click)="close()">
        CLOSE
      </button>

       ...
  </div>
</div>


所以我已经找到了一个解决办法。但是,如果有更好的方法,我就让问题公开了

根据我的理解:离开动画是(*=>void)的捷径。*是“任何状态”,void是“标记不可见”。因此,当一个组件从DOM中移除时,它是不可见的,但动画仍然不工作,因为元素不再存在(我的假设)

因此,我为模态父元素提供了一个ngIf标志:

<div *ngIf="showModal" [@modalSlideInOut] role="document" class="modal-dialog">

300是组件移除之前的等待时间,因为我的动画需要0.3秒。

我今天遇到了类似的问题,我找到的解决方案是通过以下方式将动画绑定到宿主组件本身:

@HostBinding('@modalSlideInOut')

这样,您就不必对动画计时进行任何欺骗。当您调用destroy时,Angular知道组件正在离开,因此它会为您处理它,就像您在组件上调用ngIf一样。

请提供一个解决方案。你很好地解释了你的问题,但现在,你的问题是一个寻求调试帮助的
问题(“为什么这段代码不起作用?”)
类型的问题(这些问题可能会被解决)。@trichetriche好的,我会试试。。我知道这是一个很老的问题,但这是我见过的这么多问题的一个很好的答案。谢谢
  close() {
    this.showModal = false;
    setTimeout(() => {
      this.closeCallback();
    }, 300);
  }
@HostBinding('@modalSlideInOut')