新渲染元素的动画,但不在页面加载时

Posted

技术标签:

【中文标题】新渲染元素的动画,但不在页面加载时【英文标题】:Animation for newly rendered elements, but not on page load 【发布时间】:2017-08-08 10:40:00 【问题描述】:

我订阅了 Firebase 实时数据库,因此当我向它提交内容时,它会立即呈现在视图中,而无需任何 jQuery 或 ajax。

我想对这些元素的渲染进行动画处理,这样当一个新元素被添加到 DOM 时,它的divbackground-color 是绿色的并且会慢慢消失。我不希望此类的所有divs 在加载时执行此动画。

我知道怎么做前者:

@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】:

添加一个触发器,用于检查项目通过网络时的状态。这里我在itemStatenew 时触发动画。

    trigger('itemState', [
      transition('* => new', animate(5000, keyframes([
        style( backgroundColor: 'red', offset: 0 ),
        style( backgroundColor: '*', offset: 1.0 )
      ]))),

为您的触发器提供对项目状态的引用,并在动画结束时将其设置为 null。

&lt;div [@itemState]="someItem.itemState" (@itemState.done)="someItem.itemState=''"&gt;

请务必在您的帖子中添加itemState 属性,以便您可以将它们标记为新帖子!

【讨论】:

如果您没有使用某种本地数据存储,那么您将不得不对 itemState.done 进行 API 调用 例如:(@itemState.done)="someApiCall() 将项目状态设置为 null 或 @987654328 @ 在 API 级别以及在本地将其设置为 oldnull 是的,我想我只是进行数据库调用。同样,我使用的是 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 版本,非常简单。

以上是关于新渲染元素的动画,但不在页面加载时的主要内容,如果未能解决你的问题,请参考以下文章

虚拟滚动技术 --- 解决加载大量列表DOM导致页面卡顿

新“页面加载”时 Firefox 中的 Choppy 和 Jerky CSS3 动画

动画图片预加载

渲染页面/加载所有组件时的事件

页面加载时自动为页面的背景颜色设置动画[重复]

无法传递参数以加载JSTree(重新渲染)