angular - 如何拦截:enter & :leave Animations in Angular with a changes Diff?

标签 angular angular-animations

我的模板中有一个列表,其中将显示前 3 个项目,其余项目处于可折叠状态,即在“显示更多”链接中。

  • 第 1 项
  • 项目2
  • item3

    显示更多

这是单击“显示更多”时的样子:

  • 第 1 项
  • 项目2
  • 第 3 项
  • 项目4
  • item5

    少显示

该列表是高度动态的。 这些项目由名为 myList 的单个列表中的组件保存。可折叠来 self 们的模式库,其中预定义了 html 结构。所以我实际上不得不在我的模板中有 2 个不同的列表。第一个用于前 3 个项目,第二个用于可折叠的其余项目。为了不使用相同的 HTML 两次,我使用 ng-template 定义列表并重复使用它 2 次。这是模板的粗略结构:

<ng-template #listRef let-list>
  <ul>
    <ng-container *ngFor="let item of list; trackBy: trackByFn;">
      <li @animation>

       ...

下面是模板的用法:

<!-- first part, max 3 items -->

<ng-container *ngTemplateOutlet="listRef; context: {$implicit: myList?.slice(0,3)}"></ng-container>


<!-- second part, rest in collapsible -->

<ng-container *ngIf="lebenslaufEintraege?.length > 3">
  <div class="my-collapsible">
    <a>...</a>
    <div>..
      <ng-container
          *ngTemplateOutlet="listRef; context: {$implicit: myList?.slice(3,myList.length)}">
      </ng-container>

此外,一旦添加了新项目,它就会进入动画列表。此外,如果一个项目被删除,它会保持动画状态。这是我的动画触发器:

trigger('animation', [
  transition(':enter', [
    style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0'}),  // initial
    animate('0.5s',
      style({ height: '*', 'padding-top': '*', 'padding-bottom': '*'}))  // final
  ]),
  transition(':leave', [
    style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', opacity: 1}),  // initial
    animate('0.5s',
      style({ height: '0px', 'padding-top': '0', 'padding-bottom': '0', opacity: 0}))  // final
  ])
])

问题是,当我们有超过 3 个项目并且可折叠项打开时,所有项目都在视口(viewport)中看到。在这种情况下,当一个新项目被添加到列表的第一部分时,它进入动画,但由于列表的最后一个项目也离开第一个列表并进入第二个列表,它也是动画的,我们不这样做想要。

换句话说;如果我们有 5 个项目,并在顶部添加一个新项目,item3 将从第一个列表中删除,并添加到第二个列表中,这也会触发动画

我怎样才能阻止这个动画?

今天我发现,我们可以使用这个注解禁用单个项目的动画:

<li [@.disabled]="item.isAnimated" @animation>

但我无法想象我应该如何实现这个标志 isAnimated 的逻辑。一旦 item3 转移到 2. 列表,我必须检查它是否在之前的第一个列表中,但我没有第一个列表的先前状态。

我认为唯一可能的选择是以某种方式拦截动画,并查看列表的先前状态是否具有相同的项目,如果是则中断动画..

或者我应该从项目中删除动画,而是为我的主列表 (myList) 中的更改定义一些动画。但我不知道如何使用我的模板实现这一点。

感谢任何帮助。

最佳答案

您遇到的问题是,您无法区分某个项目是被添加到您的列表中还是只是被移动到位,因为该项目在移动或添加之前不存在于模板中。如果项目在移动到位之前就存在,那么您可以区分事件并相应地使用 [@.disabled]

一个简单但低效的解决方案是重复列表两次,并向模板传递一个指示符,通知它隐藏前三个元素或隐藏除后三个元素之外的所有元素。同样的逻辑应该用于禁用动画。

如果我们可以假设一次只能将一个元素添加到数组中,那么一种更有效的方法是只将一个额外的元素传递给模板。对于列表的顶部,传递前四个元素,对于底部,传递从索引 2 开始的所有项目。

简化的工作示例代码

<ng-container *ngTemplateOutlet="listRef; context: {$implicit: items | slice:0:3, hideIndex: 3}"></ng-container>
<ng-container *ngTemplateOutlet="listRef; context: {$implicit: items | slice:2, hideIndex: 0}"></ng-container>

<ng-template #listRef let-list let-hideIndex="hideIndex">
  <ul>
    <ng-container *ngFor="let x of list; let index = index">
      <li @animation 
          [hidden]="hideIndex == index"
          [@.disabled]="hideIndex == index">{{x}}
      </li>
    </ng-container>
  </ul>
</ng-template>

发生的事情是索引 2 和 3 的项目将同时出现在两个列表中,隐藏并在其中一个适当的地方禁用动画。如果发生转变,相应的项目现在将只出现在列表中之前隐藏它们的位置。动画不会发生,因为它们之前已经添加到 DOM 中。

我最初只尝试使用隐藏,但如果快速添加项目,则动画的尾端将显示。这就是 [@.disabled] 也被使用的原因。

关于angular - 如何拦截:enter & :leave Animations in Angular with a changes Diff?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54867591/

相关文章:

node.js - 请求 session 不持久 - Express-Session

javascript - 错误 TypeError : array. map 不是 Angular 管道中的函数

Angular CDK : Apply animations to Angular custom stepper on step change

angular - 调整 Angular Material2 sidenav 大小时没有动画

Angular 4动画到高度*

angular - 我可以为angular2中的一个组件添加两个模板吗?

Angular 5+ Material 自动完成位置错误

angular - 在 Visual Studio Code 中运行的 Angular 应用程序中,TSLint 扩展抛出错误

html - Angular 顺序路由器动画

Angular 5 动画 : How to work with :leave transition while the component is removed from DOM