在继续之前,我应该注意我之前发布了一个类似的问题,内容与此类似,但是,我认为该错误的来源是在一个内部使用了自定义组件。 ngFor循环。我已经知道这不是问题所在,因此我删除了原来的问题,以使查询更加准确,并且不会误导任何人。
我目前正在使用Ionic 5和Angular 9进行项目开发,我们必须在某些视图中使用彩票。我使用的是ngx-lottie库(https://github.com/ngx-lottie/ngx-lottie#api),出于我的目的,而不是像库的API所示,在每个视图的模板中插入彩票,而是构建了一个要包含在其他视图中的组件。该组件的代码如下:
import { Component, OnInit, OnChanges, SimpleChanges, Input } from '@angular/core';
import { AnimationItem } from 'lottie-web';
import { AnimationOptions } from 'ngx-lottie';
@Component({
selector: 'app-lottie-player',
template: `<ng-lottie
[options]="options"
[styles]="styles"
(animationCreated)="animationCreated($event)">
</ng-lottie>`,
})
export class LottiePlayerComponent implements OnInit, OnChanges {
@Input() lottieToPlay: string; // Route to the json within assets/lotties
@Input() lottieToUpdate: string; // Secondary json in case a switch is needed
@Input() animationDirection: number; // 1 for normal direction, -1 for reversed animation
@Input() dimensions: any; // Layout specifications passed from parent component
options: AnimationOptions = {
path: '',
};
styles: Partial<CSSStyleDeclaration> = {
margin: '0 auto',
};
private animationItem: AnimationItem;
constructor() { }
ngOnInit() {
this.updateAnimation();
}
ngOnChanges(changes: SimpleChanges) {
const directionChange = changes.animationDirection;
if (directionChange && !directionChange.firstChange) {
this.playAnimation(this.animationItem, directionChange.currentValue);
}
}
updateAnimation(): void {
this.options = {
...this.options,
path: this.lottieToPlay,
};
this.styles = {
...this.styles,
...this.dimensions
};
}
animationCreated(animationItem: AnimationItem): void {
this.animationItem = animationItem;
this.animationItem.autoplay = false;
this.animationItem.loop = false;
}
playAnimation(animationItem: AnimationItem, direction?: number): void {
this.animationItem = animationItem;
this.animationItem.setDirection(Math.sign(direction) === 1 ? 1 : -1);
this.animationItem.play();
}
}
该组件本质上会执行以下操作:
因此,当我将其插入这样的视图中时:
<ion-buttons slot="secondary">
<ion-button class="icon-container" (click)="changeIconAndNavigate()">
<app-lottie-player
[dimensions]="lottieClassSpecs"
[lottieToPlay]="lottieFav"
[animationDirection]="lottieAnimDirection">
</app-lottie-player>
</ion-button>
</ion-buttons>
在具有此类方法的父组件内部:
public changeIconAndNavigate() {
this.lottieAnimDirection = 1;
}
抽奖活动按预期进行。动画仅触发一次,并保持其完成的动画状态。
当我如上所述插入抽奖品,但在同一组件中多次插入而不是单个插入时,就会出现问题。我现在可以相信,造成问题的原因可能是我将原始组件构建错误了。在另一个组件中,我像这样插入了乐透播放器:
<ion-item *ngFor="let card of cards" class="card-info">
...
<ion-item lines="full">
<span class="card-span">{{ card.title }}</span>
<ion-button class="lottie-holder" (click)="toggleSingleSubscription(card)">
<app-lottie-player
[dimensions]="lottieClassSpecs"
[lottieToPlay]="lottieAdd"
[animationDirection]="lottieAnimDirection">
</app-lottie-player>
</ion-button>
</ion-item>
...
</ion-item>
可以肯定的是,我在ngFor循环外插入了另一名Lottie-player实例,以了解其反应。控制这些cards
的整个父组件只需插入它们或将它们弹出到数组中,每次插入后,我都会根据需要将this.lottieANimDirection
更改为1或-1,以便ngOnChanges在lottie组件中可以获取更改并相应地渲染动画
我希望看到的是每个乐透都单独设置动画,但是所有人都可以。因此,如果我单击底部的那个,它上面写着“订阅” ...
上面的抽奖活动也会动画。
我不仅尝试了上面卡片中的一个,而且尝试使用的测试目的<app-lottie-player>
也在动画的ngFor循环上方插入。我相信该错误的原因可能是,由于我是如何构建此基本组件的,而不是在控制器内创建播放器的一个实例,因此它正在重新更新同一单个实例,从而导致接收到的信息将显示在DOM的所有插入中,因为它们实际上都来自一个实例。但是我不知道如何解决它。
如果有人对为什么会发生这种缺陷的想法丝毫不为人知,那我真是耳目一新。
答案 0 :(得分:1)
我将所有问题都传递给同一个状态实例的事实放在一起进行了一次堆栈闪电展示。
https://stackblitz.com/edit/angular-ivy-lfckkn
div
的第一个数组在父级内部都具有一个状态,因此在一个状态中进行切换会更新所有状态。
app-card
的第二个都是自己的组件,它们都有自己的状态。请注意,由于我们仍在传递全局状态作为输入,因此在内部对其进行更改时,它不会更新其他状态,但是如果在父级进行更新,则会将新值下推给所有子级。
子组件示例
import { Component, OnInit, Input} from '@angular/core';
@Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent implements OnInit {
@Input() card: {id: number, title: string};
internalState = true;
@Input() stateFromParent: boolean;
constructor() { }
ngOnInit() {
}
toggleInternalState() {
this.internalState = !this.internalState;
this.stateFromParent = !this.stateFromParent;
}
}
子组件模板
<div style="border: 1px solid green; padding: 5px;">
<p>ID: {{card.id}}</p>
<p>Title: {{card.title}}</p>
<p>internalState: {{internalState | json}}</p>
<p>stateFromParent: {{stateFromParent | json}} (NOTE: it will mange its own internal one, but if the parent's input changes that new value will be passed in)</p>
<button (click)="toggleInternalState()">Toggle Value</button>
</div>