新渲染元素的动画,但不在页面加载时
Posted
技术标签:
【中文标题】新渲染元素的动画,但不在页面加载时【英文标题】:Animation for newly rendered elements, but not on page load 【发布时间】:2017-08-08 10:40:00 【问题描述】:我订阅了 Firebase 实时数据库,因此当我向它提交内容时,它会立即呈现在视图中,而无需任何 jQuery 或 ajax。
我想对这些元素的渲染进行动画处理,这样当一个新元素被添加到 DOM 时,它的div
的background-color
是绿色的并且会慢慢消失。我不希望此类的所有div
s 在加载时执行此动画。
我知道怎么做前者:
@keyframes green-fade
0% background: rgb(173, 235, 173);
100% background: none;
.post-div
animation: green-fade 5s ease-in 1;
当然,这个动画在这个类被渲染的任何时候都会发生,包括在加载时。
我对执行此操作的“Angular 2 方式”感兴趣。
【问题讨论】:
【参考方案1】:从 Angular 4.25 开始,有一种更简单的方法可以做到这一点:如果你想在视图初始化时抑制 :enter 动画,只需用以下动画包装它:
template: `
<div [@preventInitialChildAnimations]>
<div [@someAnimation]>...</div>
</div>
`,
animations: [
trigger('preventInitialChildAnimations', [
transition(':enter', [
query(':enter', [], optional: true)
])
]),
...
]
【讨论】:
更新了接受的答案,因为它解决了当前的 Angular 版本。 在 Angular 4.2.4 中不适合我,动画仍然在页面加载时发生[@someAnimation.done]
仍被触发,导致此解决方案无法使用。
你能告诉我这个@someanimation 在TS 文件中的注册位置吗?我是角度动画的新手,面临同样的问题。【参考方案2】:
最简单的解决方案:
@Component(
selector: 'myComponent',
template: '<div [@.disabled]="disableAnimations" [@someAnimation]="someValue">',
animations: [trigger('someAnimation', [transition('* => *', [style( transform: 'scale(1.1)' ), animate(250)])])]
)
export class MyComponent implements AfterViewInit
disableAnimations: boolean = true;
constructor()
ngAfterViewInit(): void
this.disableAnimations = false;
参考: https://angular.io/api/animations/trigger (滚动到“禁用动画”)
【讨论】:
这是最好的解决方案。我尝试了 Martin Cremer 的解决方案,它在第一次加载时有效,但是当我导航到另一个组件然后返回到原始组件时,动画被触发了。 它不起作用。编译器说:“错误错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。以前的值:'@.disabled:true'。当前值:'@.disabled:false'。” 这是我唯一的解决方案。我不得不将它包装在一个(hacky)setTimeout 中以防止 ExpressionChanged 问题【参考方案3】:添加一个触发器,用于检查项目通过网络时的状态。这里我在itemState
为new
时触发动画。
trigger('itemState', [
transition('* => new', animate(5000, keyframes([
style( backgroundColor: 'red', offset: 0 ),
style( backgroundColor: '*', offset: 1.0 )
]))),
为您的触发器提供对项目状态的引用,并在动画结束时将其设置为 null。
<div [@itemState]="someItem.itemState" (@itemState.done)="someItem.itemState=''">
请务必在您的帖子中添加itemState
属性,以便您可以将它们标记为新帖子!
【讨论】:
如果您没有使用某种本地数据存储,那么您将不得不对 itemState.done 进行 API 调用 例如:(@itemState.done)="someApiCall()
将项目状态设置为 null
或 @987654328 @ 在 API 级别以及在本地将其设置为 old
或 null
。
是的,我想我只是进行数据库调用。同样,我使用的是 AngularFire,所以数据库中项目状态的变化是实时反映的。
当然,这只会在发布帖子时向查看页面的用户显示动画。嗯,也许是在经过一段时间后调用 API 的东西?
相反,我会亲自创建一个 firebase 函数,它遍历数据库中帖子的日期和时间,并相应地为每个项目的 itemState
属性设置 new
标志。【参考方案4】:
您可以使用生命周期挂钩 AfterViewInit 在初始视图渲染完成后激活动画。
https://embed.plnkr.co/5l1kf5lMLEXSE8pNzqik/
@Component(
selector: 'my-app',
template: `
<div *ngFor="let item of items" [@greenFade]="animate ? 'in' : null">
item
</div>
<button (click)="addItem()">add</button>
`,
animations: [
trigger('greenFade', [
transition('void => in', [style(background: 'rgb(173, 235, 173)'), animate('5s ease-in')])
])
]
)
class App implements AfterViewInit
constructor(private cdRef: ChangeDetectorRef)
items: String = ['Item','Item','Item'];
addItem()
this.items.push('Item');
animate: boolean;
ngAfterViewInit()
this.animate = true;
this.cdRef.detectChanges();
【讨论】:
这不会在每次渲染视图时触发动画吗? 是什么让你这么认为?每个项目的动画被触发,当它的@greenFade 属性从void 变为'in',换句话说:如果它的第一个值是'in'。这种情况只发生一次。对于初始项目,它根本不会发生。它们从 void 变为 null,然后从 null 变为“in”。 哦,你是对的!让我看看这个与公认答案的好处。我认为最明显的当然是这不需要在后端设置任何值。我想这取决于你的用例。 这在 Angular 4 中对我不起作用。我想知道语法是否发生了变化。 试试我刚刚给出的新答案,它指的是最新的 Angular 版本,非常简单。以上是关于新渲染元素的动画,但不在页面加载时的主要内容,如果未能解决你的问题,请参考以下文章