web-dev-qa-db-ja.com

Angular 2 Slide Up and Down Animation

最近、次のAngular 2 Read Moreコンポーネントを作成しました。このコンポーネントは、「Read more」リンクと「Read Less」リンクを使用して長いテキストブロックを折りたたんだり展開したりします。文字数。ただし、指定された最大の高さに基づいています。

import { Component, Input, ElementRef, AfterViewInit } from '@angular/core';

@Component({
    selector: 'read-more',
    template: `
        <div [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'">
        </div>
            <a *ngIf="isCollapsable" (click)="isCollapsed =! isCollapsed">Read {{isCollapsed? 'more':'less'}}</a>
    `,
    styles: [`
        div.collapsed {
            overflow: hidden;
        }
    `]
})
export class ReadMoreComponent implements AfterViewInit {

    //the text that need to be put in the container
    @Input() text: string;

    //maximum height of the container
    @Input() maxHeight: number = 100;

    //set these to false to get the height of the expended container 
    public isCollapsed: boolean = false;
    public isCollapsable: boolean = false;

    constructor(private elementRef: ElementRef) {
    }

    ngAfterViewInit() {
        let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight;
       //collapsable only if the contents make container exceed the max height
        if (currentHeight > this.maxHeight) {
            this.isCollapsed = true;
            this.isCollapsable = true;
        }
    }
}

そして次のように使用されます:

<read-more [text]="details" [maxHeight]="250"></read-more>

コンポーネントはうまく機能します。次に、コンポーネントにスライドアップ/ダウンアニメーションを追加して、[続きを読む]リンクをクリックするとコンテンツが下にスライドし、[次を読む]をクリックするとコンテンツが指定の最大高さまでスライドするようにする必要があります。

誰でもこれを達成する方法を教えてもらえますか?

9
Naveed Ahmed

:enter:leave、および*ngIfを使用した私のソリューション:

@Component({
    selector: 'accordion',
    templateUrl: './accordion.component.html',
    animations: [
        trigger('slideInOut', [
            state('in', style({height: '*', opacity: 0})),
            transition(':leave', [
                style({height: '*', opacity: 1}),

                group([
                    animate(300, style({height: 0})),
                    animate('200ms ease-in-out', style({'opacity': '0'}))
                ])

            ]),
            transition(':enter', [
                style({height: '0', opacity: 0}),

                group([
                    animate(300, style({height: '*'})),
                    animate('400ms ease-in-out', style({'opacity': '1'}))
                ])

            ])
        ])
    ]
})
...

テンプレート:

<div *ngIf="shown" [@slideInOut] >
    // ...content
</div>

残念ながら、この修正も組み込む必要がありました(slideOutの場合): https://github.com/angular/angular/issues/15798

14
Felix

自動プロパティ計算

自動高さ計算によるアニメーション

場合によっては、実行時まで次元スタイルプロパティの値がわからないことがあります。たとえば、要素の幅と高さは、多くの場合、コンテンツと画面サイズに依存します。これらのプロパティは、CSSでアニメーション化するのが難しい場合があります。

これらの場合、特別な*プロパティ値を使用して、実行時にプロパティの値が計算され、アニメーションにプラグインされるようにすることができます。

この例では、leaveアニメーションは、要素が離れる前の要素の高さをすべて取得し、その高さからゼロまでアニメーション化します。

animations: [
  trigger('shrinkOut', [
    state('in', style({height: '*'})),
    transition('* => void', [
      style({height: '*'}),
      animate(250, style({height: 0}))
    ])
  ])
]

from Angular公式ドキュメント(現在はアーカイブ)): https://v2.angular.io/docs/ts/latest/guide/animations.html#!#automatic-プロパティ計算

14
Julien

Threeveの答えは正しいです。唯一の問題は、CSSトランジションが「auto」で機能しないことです。そのため、ngAfterViewInit関数で自動高さをキャプチャし、文字列として保存する必要があります。また、発生する可能性のある「単方向データフロー違反エラー」を停止するためにsetTimeout関数を使用していることに注意してください。

import { Component, Input, ElementRef, AfterViewInit } from '@angular/core';

@Component({
selector: 'read-more',
template: `
    <div [style.height]="isCollapsed ? maxHeight+'px' : autoHeight">
        <ng-content></ng-content>
    </div> 

    <span *ngIf="isCollapsable" class="btn-link cpointer" (click)="isCollapsed =! isCollapsed">Read {{isCollapsed? 'more':'less'}} ...</span>

    `,
styles: [` div { overflow-y: hidden; 
          -moz-transition: height .5s;
          -ms-transition: height .5s;
          -o-transition: height .5s;
          -webkit-transition: height .5s;
          transition: height .5s; ease;}
         .cpointer {cursor:pointer; }
        `]
})
export class ReadMoreComponent implements AfterViewInit {

@Input()
maxHeight: number = 40; //two lines

////set these to false to get the height of the expended container 
isCollapsed: boolean = false;
isCollapsable: boolean = false;
autoHeight: string= "auto";

constructor(private elementRef: ElementRef) {}

ngAfterViewInit() {
    // Inportant !!
    // wait a tick to avoid one-time devMode
    // unidirectional-data-flow-violation error
    setTimeout(_ => {
            let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight;

            this.autoHeight = currentHeight + "px";
            //collapsable only if the contents make container exceed the max height
            if (currentHeight >= this.maxHeight) {
                this.isCollapsed = true;
                this.isCollapsable = true;
            }
        }
    );
}

}
2
Ron Brill

これは、私がAngular 8.1.2で使用するものです。コードの美しさは、表示/折りたたみが必要なdivの無制限の高さをサポートし、スムーズなトランジションも行うことです。

TSファイル:

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

@Component({
    selector: 'app-all-data',
    templateUrl: './all-data.page.html',
    styleUrls: ['./all-data.page.scss'],
    animations: [
        trigger('openClose', [
            state('open', style({
                height: '*',
                opacity: 1,
            })),
            state('closed', style({
                height: '0',
                opacity: 0
            })),
            transition('open => closed', [
                animate('0.35s')
            ]),
            transition('closed => open', [
                animate('0.35s')
            ]),
        ]),
    ]
})
export class AllDataPage implements OnInit {

    showCardBody = false;

    constructor() {
    }

    ngOnInit() {
    }

    /**
     * Toggle details on click
     */
    showDetails() {
        this.showCardBody = !this.showCardBody;
    }

}

HTMLファイル:

<button type="button" (click)="showDetails()">
       Toggle Details
</button>

<div class="card-body" [@openClose]="showCardBody ? 'open' : 'closed'">
       <p>This is some content</p>
       <p>This is some content</p>
       <p>This is some content</p>       
       <p>This is some content</p>
       <p>This is some content</p>
</div>
1
Devner