ng-bootstrap collapse: How to apply animations?

╄→尐↘猪︶ㄣ 提交于 2020-12-29 09:14:30

问题


I'm using Collapse: https://ng-bootstrap.github.io/#/components/collapse

However, it does not animate; even not on the demo site. How should I implement this??


回答1:


Here's a good way to do it, I think, and it works both for revealing and collapsing: (though it doesn't really need ng-bootstrap anymore)

template.html:

<button (click)="isCollapsed = !isCollapsed">Toggle</button>
<p [@smoothCollapse]="isCollapsed?'initial':'final'">
    your data here
</p>

.

component.ts:

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

@Component({
  selector: 'app-my-component',
  templateUrl: './template.html',
  styleUrls: ['./style.scss'],
  animations: [
    trigger('smoothCollapse', [
      state('initial', style({
        height:'0',
        overflow:'hidden',
        opacity:'0'
      })),
      state('final', style({
        overflow:'hidden',
        opacity:'1'
      })),
      transition('initial=>final', animate('750ms')),
      transition('final=>initial', animate('750ms'))
    ]),
  ]
})
export class MyComponent ...

Details:

  • initial height:0 allows to start from nothing
  • not specifying a final height let the element stop growing when it's all displayed
  • overflow:hidden everywhere so your element doesn't run on other elements
  • opacity from 0 to 1 makes it nicer (in my opinion)
  • An important thing which took me some time to realize is to NOT put [ngbCollapse]="isCollapsed" in the <p> otherwise it breaks all the animation. And we don't need it since we set the height to 0

Hope it helps, I spent a day on it :P




回答2:


Because they use "display: none" to hide and "display: block" to show element, you can't apply "transition" CSS property.

So, force display block, manage height & opacity to toggle hide/show :

.collapse, .collapse.in {
  display: block !important;
  transition: all .25s ease-in-out;
}

.collapse {
 opacity: 0;
 height: 0;
}

.collapse.in {
  opacity: 1;
  height: 100%;
}

With basic transition and opacity/height, it seem to be more smooth.

You can make your own animation with keyframe and apply to .collapse.in to get better toggle hide/show experience.

And then, if you use Angular 2 in your project, you can switch to ng2-bootstrap : http://valor-software.com/ng2-bootstrap/




回答3:


inside your component you can add something like this:

 animations: [
    trigger('expandCollapse', [
                state('open', style({height: '100%', opacity: 1})),
                state('closed', style({height: 0, opacity: 0})),
                transition('* => *', [animate('100ms')])
            ]),
 ]


 <div [ngbCollapse]="isCollapsed" [@expandCollapse]="isCollapsed ? 'closed' : 'open'"> ... </div>

See more details here https://angular.io/guide/animations#animating-a-simple-transition




回答4:


I've created a directive using only bootstrap classes that performs the same original bootstrap effect using only angular-animation, check it out!

Live example

Directive code

import {Directive, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import {animate, AnimationBuilder, AnimationPlayer, keyframes, style} from '@angular/animations';

@Directive({
  selector: '[appCollapseAnimated]'
})
export class CollapseAnimatedDirective implements OnChanges, OnInit {
  private static readonly SHOW_STYLE = 'show';
  private static readonly COLLAPSING = 'collapsing';

  @Input('appCollapseAnimated')
  collapsed = true;

  @Input()
  skipClosingAnimation = false;

  @HostBinding('class.collapse')
  private readonly addCollapseClass = true;

  private currentEffect: AnimationPlayer;
  private _closeEffect: AnimationPlayer;
  private _openEffect: AnimationPlayer;

  constructor(private el: ElementRef,
              private builder: AnimationBuilder) {

  }

  ngOnInit(): void {
    if (!this.collapsed) {
      this.getClassList().add(CollapseAnimatedDirective.SHOW_STYLE);
    }
  }

  private get openEffect(): AnimationPlayer {
    if (!this._openEffect) {
      this._openEffect = this.builder.build(animate('500ms', keyframes([
        style({height: '0'}),
        style({height: '*'}),
      ]))).create(this.el.nativeElement);
    }
    this._openEffect.onDone(() => this.effectDone());
    return this._openEffect;
  }


  private get closeEffect(): AnimationPlayer {
    if (!this._closeEffect) {
      this._closeEffect = this.builder.build(animate('500ms', keyframes([
        style({height: '*'}),
        style({height: '0'}),
      ]))).create(this.el.nativeElement);
    }
    this._closeEffect.onDone(() => this.effectDone());
    return this._closeEffect;
  }

  private effectDone() {
    if (this.collapsed) {
      this.getClassList().remove(CollapseAnimatedDirective.SHOW_STYLE);
    }
    this.getClassList().remove(CollapseAnimatedDirective.COLLAPSING);
    if (this.currentEffect) {
      this.currentEffect.reset();
      this.currentEffect = null;
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.collapsed && !changes.collapsed.firstChange) {
      if (changes.collapsed.previousValue === true && changes.collapsed.currentValue === false) {
        this.startOpening();
      }
      if (changes.collapsed.previousValue === false && changes.collapsed.currentValue === true) {
        this.startClosing();
      }
    }
  }

  private startOpening(): void {
    this.getClassList().add(CollapseAnimatedDirective.SHOW_STYLE);
    const effect = this.openEffect;
    this.playEffect(effect);
  }

  private getClassList() {
    const nativeElement = this.el.nativeElement as HTMLElement;
    return nativeElement.classList;
  }

  private startClosing(): void {
    const effect = this.closeEffect;
    if (this.skipClosingAnimation) {
      this.effectDone();
    } else {
      this.playEffect(effect);
    }
  }

  private playEffect(effect: AnimationPlayer) {
    if (!this.currentEffect) {
      this.getClassList().add(CollapseAnimatedDirective.COLLAPSING);
      this.currentEffect = effect;
      this.currentEffect.play();
    }
  }
}

Use it in your template:

<button class="btn btn-primary" (click)="collapsed = !collapsed">
  Toggle
</button>
<div [appCollapseAnimated]="collapsed" class="beautiful-div border border-secondary mt-5">
  this should collapse with the default bootstrap behaviour
</div>


来源:https://stackoverflow.com/questions/40142922/ng-bootstrap-collapse-how-to-apply-animations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!