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: none
和 display: block
之间切换元素显示样式,您可以 see in the source。对显示 属性 的这种更改使过渡动画无效(至少目前,浏览器在显示 属性 更改时不遵守过渡)。
看起来折叠实现的预期默认行为是有动画,但有一个障碍。由于崩溃的 ng2-bootstrap 实现使用指令,他们正在等待 Angular 2+ 对指令动画的支持,这不存在——至少现在还不存在(但在组件上存在,就像你一样)目前正在使用)。这是一个已知问题,已报告 here。
解决方法:
您表示您打算在多个地方使用动画,这表明您可以从使动画可重用中获益 -- 这将使事情变得更 DRY 并且更易于管理。在为需要动画的时候弄乱了一堆解决方法选项之后,我认为最好的方法是:
- 不要对模板中需要动画进出的项目使用 ng2-bootstrap 的折叠指令。在您的示例中,
[collapse]=isCollapsed()
(正如您已经确定的那样)。
- 像现在一样在组件上指定动画。
- 创建一个 class 来定义您的动画,使它们可以重新使用。
- 将#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>
我知道由于 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: none
和 display: block
之间切换元素显示样式,您可以 see in the source。对显示 属性 的这种更改使过渡动画无效(至少目前,浏览器在显示 属性 更改时不遵守过渡)。
看起来折叠实现的预期默认行为是有动画,但有一个障碍。由于崩溃的 ng2-bootstrap 实现使用指令,他们正在等待 Angular 2+ 对指令动画的支持,这不存在——至少现在还不存在(但在组件上存在,就像你一样)目前正在使用)。这是一个已知问题,已报告 here。
解决方法:
您表示您打算在多个地方使用动画,这表明您可以从使动画可重用中获益 -- 这将使事情变得更 DRY 并且更易于管理。在为需要动画的时候弄乱了一堆解决方法选项之后,我认为最好的方法是:
- 不要对模板中需要动画进出的项目使用 ng2-bootstrap 的折叠指令。在您的示例中,
[collapse]=isCollapsed()
(正如您已经确定的那样)。 - 像现在一样在组件上指定动画。
- 创建一个 class 来定义您的动画,使它们可以重新使用。
- 将#2 中的动画设置为#3 中的适当对象。
这是一个例子:
animations.tsimport { 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>