在 Angular 4 中动画图像交换(在 AngularJS 中是 ng-animate-swap)

Posted

技术标签:

【中文标题】在 Angular 4 中动画图像交换(在 AngularJS 中是 ng-animate-swap)【英文标题】:Animate an image swap in Angular 4 (Was ng-animate-swap in AngularJS) 【发布时间】:2018-05-12 07:12:36 【问题描述】:

我想在 Angular 4 应用程序中为图像交换设置动画。当控制器替换 img src 属性时,旧图像应该消失并出现新图像。

在 AngularJS 中,这可以通过使用 ng-animate-swap 更改不透明度来实现。但是,Angular 4 似乎不支持动画交换。如果没有交换触发器,如何实现这一点?

我尝试为 src 属性添加从 void 到 * 并返回的转换,但这不能按预期工作。第一张图片是动画的,后来交换发生时没有动画。

@Component(
  selector: 'app-play-card',
  template: '<div (click)="loadImg()"><img [@fade]="imgsrc" src=" imgsrc " /></div>',
  styleUrls: ['./play-card.component.css'],
  animations: [
    trigger('fade', [
      transition('void => *', [
        style(opacity: 0.1),
        animate(5000, style(opacity: 1))
      ]),
      transition('* => void', [
        style(opacity: 0.9),
        animate(5000, style(opacity: 0))
      ])
    ])
  ]
)

【问题讨论】:

***.com/questions/64848450/… 【参考方案1】:

这是我使用 Angular 动画状态的方法:

animations.ts

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

export const fade = [
  trigger('fade', [
    state('in', style( 'opacity': '1' )),
    state('out', style( 'opacity': '0' )),
    transition('* <=> *', [
      animate(1000)
    ])
  ])
];

app.component.html

<img [@fade]="state" (@fade.done)="onDone($event)" [src]="imageSource"  (click)="onClick()" />

我使用了(@fade.done),这是 Angular 动画的一个功能,允许您在动画完成后调用方法。

在这里,一旦第一个动画褪色到不透明度为 0,我更改了图像路径,并更改了动画状态,再次褪色并将不透明度值恢复为 1。

app.component.ts

export class AppComponent implements OnInit 
  choice = 2;
  state = 'in';
  counter = 0;
  enableAnimation = false;
  imageSource = '';
  imgSrc1 = 'firstPath';
  imgSrc2 = 'secondPath';

  ngOnInit() 
    this.imageSource = this.imgSrc1;
  

  onClick() 
    this.enableAnimation = true;
    this.counter = 0;
    this.toggleState();
  

  toggleImg() 
    if (this.choice === 1) 
      this.imageSource = this.imgSrc1;
      this.choice = 2;
     else 
      this.imageSource = this.imgSrc2;
      this.choice = 1;
    
  

  onDone($event) 
    if (this.enableAnimation) 
      if (this.counter === 1) 
        this.toggleImg();
      
      this.toggleState();
    
  

  toggleState() 
    if (this.counter < 2) 
      this.state = this.state === 'in' ? 'out' : 'in';
      this.counter++;
    
  

这显然是一个小动画的大量代码。

这是我为此制作的 StackBlitz 示例:https://stackblitz.com/edit/angular-anim-fade-img

【讨论】:

不幸的是,这个解决方案毕竟不实用。我的图像是通过慢速网络加载的,并且在淡出完成时不在缓存中。结果,当调用切换图像并开始淡入淡出阶段时,我会在短时间内继续看到旧图像。仅在明显延迟后,新图像加载完成并替换旧图像。淡入淡出在这一点上如火如荼。 您可以通过在文档中抓取“img”元素并等待“完成”来解决此问题。使用两个图像元素(而不是一个)。开始在背景中加载“切换”图像(将其不透明度保持为 0 直到它“完成”),然后您就可以真正启用淡入动画了!【参考方案2】:

我确实尽可能地过滤掉,以免代码过载。 我希望代码足够简单,您可以集成它。

gallery.component.ts:

import  Component, Input  from '@angular/core';
import  trigger, style, animate, transition  from '@angular/animations';

const animations = trigger('imgAnimation', [
    transition(':enter', [
        style( opacity: 0 ),
        animate('500ms', style( opacity: 1 )),
    ]),
    transition(':leave', [
        animate('300ms', style( opacity: 0 ))
    ])
]);

@Component(
    selector: 'app-gallery',
    templateUrl: './gallery.component.html',
    styleUrls: [],
    animations: [animations]
)
export class GalleryComponent 
    @Input() images: string[];

    index: number = 0;
    imageIndex: number = 0;

    onIncIndex(increment: number = 1) 
        this.index = (this.index + this.images.length + increment) % this.images.length;
        this.imageIndex = null;
    

    onDone() 
        this.imageIndex = this.index;
    

gallery.component.html:

<picture>
    <ng-container *ngFor="let img of images; index as i">
        <img *ngIf="i === imageIndex" 
             @imgAnimation
             (@imgAnimation.done)="onDone()"
             [src]="img">
    </ng-container>
</picture>

<div>
    <button (click)="onIncIndex(-1)">Previous</button>
    <button (click)="onIncIndex()">Next</button>
</div>

【讨论】:

【参考方案3】:

如果您正在使用 2 张图片....您可以这样做..

<mat-icon>
  <img
    [@fadeIn]
    *ngIf="myBool"
    src="assets/svg-icons/back.svg"
    
  />
  <img
    [@fadeIn]
    *ngIf="!myBool"
    src="assets/svg-icons/close.svg"
    
  />
</mat-icon>

您将只想为进入状态设置动画,否则对于一个实例,两个图像将并排显示

trigger('fadeIn', [
  transition(':enter', [style( opacity: 0 ), animate(160)]),
  // transition(':leave', [animate(160, style( opacity: 0 ))]),
]),

您可以解决问题并将图像设为绝对,然后您可以为进入和离开状态设置动画(因为这次图像将相互重叠)

【讨论】:

以上是关于在 Angular 4 中动画图像交换(在 AngularJS 中是 ng-animate-swap)的主要内容,如果未能解决你的问题,请参考以下文章

使用 jQuery 编写图像动画(交换图像)

jQuery 动画图像交换

另一个 div 后面的绝对图像动画 - Angular 5 动画

Angular 4 平滑动画

用于淡入和淡出视图的 Angular 4 动画

如何在 Angular 2 中执行无限动画?