angular2 ng2-bootstrap 折叠动画解决方法

angular2 ng2-bootstrap collapse animation workaround

我知道由于 angular2 的指令动画支持不可用,当前 ng2-bootstrap 中的动画代码被注释掉的问题。

因此我通过在我的组件中使用 angular2 的 animate 创建了一个解决方法。

animations: [
  trigger('slideMenu', [
    state('true', style({ height: '0px' })),
    state('false', style({ height: '*' })),
    transition('1 => 0', animate('200ms ease-in')),
    transition('0 => 1', animate('200ms ease-out'))
  ]),
]

更新:我有plunker示例:https://plnkr.co/edit/iVffRLUhzp43DXo5BYlJ?p=preview(如果加载示例失败,请多次单击停止和运行按钮。它最终会起作用)。

我想让上面的动画代码在展开时创建滑出效果,在折叠时创建滑入效果。但是,动画仅在展开时有效。当我尝试折叠菜单时,它就消失了,没有任何动画。

我想知道是否有人曾尝试为 slide-int 和 slide-out 的菜单垂直折叠创建一个可行的解决方法。

提前致谢。

您实际上已经弄清楚发生了什么,但我深入了解并提供了一些额外的详细信息,说明您为什么会看到这些结果,以及对变通办法的改进,它更简洁、可重复使用。

根本原因:

如您所述,ng2-bootstrap 当前的折叠实现只是在 display: nonedisplay: block 之间切换元素显示样式,您可以 see in the source。对显示 属性 的这种更改使过渡动画无效(至少目前,浏览器在显示 属性 更改时不遵守过渡)。

看起来折叠实现的预期默认行为是有动画,但有一个障碍。由于崩溃的 ng2-bootstrap 实现使用指令,他们正在等待 Angular 2+ 对指令动画的支持,这不存在——至少现在还不存在(但在组件上存在,就像你一样)目前正在使用)。这是一个已知问题,已报告 here

解决方法:

您表示您打算在多个地方使用动画,这表明您可以从使动画可重用中获益 -- 这将使事情变得更 DRY 并且更易于管理。在为需要动画的时候弄乱了一堆解决方法选项之后,我认为最好的方法是:

  1. 不要对模板中需要动画进出的项目使用 ng2-bootstrap 的折叠指令。在您的示例中,[collapse]=isCollapsed()(正如您已经确定的那样)。
  2. 像现在一样在组件上指定动画。
  3. 创建一个 class 来定义您的动画,使它们可以重新使用。
  4. 将#2 中的动画设置为#3 中的适当对象。

这是一个例子:

animations.ts
import { trigger, state, transition, animate, style } from '@angular/core';

export class Animations {
    public static slideInOut = trigger('slideInOut', [
        state('true', style({ height: '0px' })),
        state('false', style({ height: '*' })),
        transition('1 => 0', animate('500ms ease-in')),
        transition('0 => 1', animate('500ms ease-out'))
    ]);
}
app.component.ts
import { Component, trigger, state, style, transition, animate } from '@angular/core';
import { Animations } from './animations';

@Component({
  selector: 'my-app',
  templateUrl: './app/app.component.html',
  styleUrls: ['./app/app.component.css'],
  animations: [ Animations.slideInOut ]
})
export class AppComponent { 
  private collapsed: boolean;

  constructor() {
    this.collapsed = true;
  }

  public isCollapsed(): boolean {
    return this.collapsed;
  }

  public setCollapsed(): void {
    this.collapsed = true;
  }

  public toggleMenu(): void {
    this.collapsed = !this.collapsed;
  }
}
app.component.html
<header>
    <nav class="navbar navbar-fixed-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" (click)="toggleMenu()">
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
            </div>
        </div>
    </nav>

    <nav role="navigation" class="navbar-fixed-top-responsive">
        <div class="vertical-menu" [@slideInOut]="isCollapsed()">
            <ul class="menu-item">
                <li><a>menu1</a></li>
                <li><a>menu2</a></li>
                <li><a>menu3</a></li>
            </ul>
        </div>
    </nav>
</header>