DOMを出入りする際のエキスパンドとクローズをアニメーション化するパネルを正常に取得しました。問題は、詳細を表示する前にパネル内にビジーインジケータがあり、アニメーションはビジーインジケータを開くときにのみ発生し、詳細コンテンツが表示されるとスナップすることです。
Angularアニメーションを取得して、高さの変化をアニメーション化するにはどうすればよいですか?
ここに例を示します: https://plnkr.co/edit/Bs0rwp4ElidR75zN3ulR
trigger('expandCollapseDetails', [
state('void', style({
'height': '0px',
overflow: 'hidden'
})),
//element being added into DOM.
transition(':enter', [
animate('500ms ease-in-out', style({
'height': '*',
overflow: 'hidden'
}))
]),
//element being removed from DOM.
transition(':leave', [
animate('500ms ease-in-out', style({
'height': '0px',
overflow: 'hidden'
}))
])
])
コンテンツが変更された場合に投影されるコンテンツの高さをスムーズにアニメーション化するコンポーネントを作成しました。次のように使用されます。
<smooth-height [trigger]="content">
{{content}}
</smooth-height>
ここにstackblitzがあります: https://stackblitz.com/edit/angular4-kugxw7
これはコンポーネントです:
import {ElementRef, HostBinding, Component, Input, OnChanges} from '@angular/core';
import {animate, style, transition, trigger} from "@angular/animations";
@Component({
selector: 'smooth-height',
template: `
<ng-content></ng-content>
`,
styles: [`
:Host {
display: block;
overflow: hidden;
}
`],
animations: [
trigger('grow', [
transition('void <=> *', []),
transition('* <=> *', [
style({height: '{{startHeight}}px', opacity: 0}),
animate('.5s ease'),
], {params: {startHeight: 0}})
])
]
})
export class SmoothHeightComponent implements OnChanges {
@Input()
trigger: any;
startHeight: number;
constructor(private element: ElementRef) {}
@HostBinding('@grow') get grow() {
return {value: this.trigger, params: {startHeight: this.startHeight}};
}
setStartHeight(){
this.startHeight = this.element.nativeElement.clientHeight;
}
ngOnChanges(){
this.setStartHeight();
}
}
@MartinCremerの回答に基づいてディレクティブを作成しました。ディレクティブを使用する方がより理にかなっていると思います。それを行うことで、親コンポーネントにもアニメーションを追加する必要があります(そして、アニメーションを追加する標準的な方法に近い)。
だから私のanimations.ts
ファイル。アニメーションを追加しました:
export const smoothHeight = trigger('grow', [
transition('void <=> *', []),
transition('* <=> *', [style({ height: '{{startHeight}}px', opacity: 0 }), animate('.5s ease')], {
params: { startHeight: 0 }
})
]);
次に、このアニメーションを親コンポーネント(内部でアニメーションを使用するコンポーネント)に追加する必要があります。
import { smoothHeight } from '@app/animations';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss'],
animations: [smoothHeight]
})
そして、@ MartinCremerのコンポーネントに本当に近いディレクティブは次のとおりです。
import { Directive, OnChanges, Input, HostBinding, ElementRef } from '@angular/core';
@Directive({
selector: '[smoothHeight]',
Host: { '[style.display]': '"block"', '[style.overflow]': '"hidden"' }
})
export class SmoothHeightAnimDirective implements OnChanges {
@Input()
smoothHeight;
Pulse: boolean;
startHeight: number;
constructor(private element: ElementRef) {}
@HostBinding('@grow')
get grow() {
return { value: this.Pulse, params: { startHeight: this.startHeight } };
}
setStartHeight() {
this.startHeight = this.element.nativeElement.clientHeight;
}
ngOnChanges(changes) {
this.setStartHeight();
this.Pulse = !this.Pulse;
}
}
最後にparent.component.html
ディレクティブを使用します。
<div [smoothHeight]="yourAnimationIndicator">
// any html content goes here
</div>
yourAnimationIndicator
を、値の変更時にアニメーションがトリガーする変数に置き換えるだけです。
あなたは少しのCSSとJSで似たようなことを達成できます:
import { Component, OnChanges, ViewChild, Input } from '@angular/core';
@Component({
selector: 'app-exandable',
templateUrl: './exandable.component.html',
styleUrls: ['./exandable.component.css']
})
export class ExandableComponent implements OnChanges {
@Input()
src;
@ViewChild('expandable')
expandable;
ngOnChanges() {
this.updateHeight();
}
updateHeight(delay = 0) {
const el = this.expandable.nativeElement;
setTimeout(() => {
const prevHeight = el.style.height;
el.style.height = 'auto';
const newHeight = el.scrollHeight + 'px';
el.style.height = prevHeight;
setTimeout(() => {
el.style.height = newHeight;
}, 50);
}, delay);
}
}
.expandable {
transition: height 0.2s ease-in-out;
overflow: auto;
}