我的模板中有一个列表,其中将显示前3个项目,其余项目位于可折叠状态,即在“显示更多”链接中。
item3
显示更多
单击“显示更多”后,外观如下:
item5
显示较少
该列表是高度动态的。 项目由组件保存在名为myList的单个列表中。。可折叠来自我们的模式库,其中的HTML结构是预定义的。因此,实际上我的模板中必须有 2个不同的列表。首先是前三个项目,第二个是可折叠项目中的其余项目。为了避免两次使用相同的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个以上的项目并且可折叠对象处于打开状态时,所有项目都可以在视口中看到。在这种情况下,将新项目添加到列表的第一部分时,它会进入动画状态,但是由于列表的最后一项也离开了第一个列表并进入第二个列表,因此它也会被动画化,我们不会想要。
换句话说;如果我们有5个项目,并在顶部添加一个新项目,则将item3从第一个列表中删除,然后添加到第二个列表中,这也会触发动画。
如何防止此动画?
今天我发现,我们可以使用以下注释为单个项目禁用动画:
<li [@.disabled]="item.isAnimated" @animation>
但是我无法想象我应该如何实现此标志isAnimated的逻辑。将item3移至2.列表后,我必须检查它之前是否在第一个列表中,但我没有第一个列表的先前状态。
我认为唯一可能的选择是以某种方式截获动画,并查看列表的先前状态是否具有相同的项目,如果是,则中断动画。.
或者我应该从项目中删除动画,而是为我的主列表(myList)中的更改定义一些动画。但是我不知道如何在我的模板中实现这一目标。
感谢您的帮助。
答案 0 :(得分:3)
您遇到的问题是,您无法区分是将项目添加到列表中还是只是将其转移到适当位置,因为在转移或添加之前模板中不存在该项目。如果该项目在转移到位之前就已经存在,那么您可以区分事件并相应地使用[@.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]
的原因。
答案 1 :(得分:0)
与您的方法略有不同。不确定它是否可以回答您的问题(拦截输入/离开动画事件),但我认为至少可以解决您的用例。
首先不维护2个数组如何?
<div *ngFor="let item of list; let i=index; trackBy: trackByFn;">
<li @animation *ngIf="i < defaultCount">
{{item.value}}
</li>
</div>
<button (click)="showMore()" *ngIf="defaultCount === 3">Show More</button>
<button (click)="showLess()" *ngIf="defaultCount !== 3">Show Less</button>
并在组件打字稿文件中。
showMore(): void {
this.defaultCount = this.list.count;
}
showLess(): void {
this.defaultCount = 3;
}
您的动画将保持原样。现在,您的功能应与动画一起使用。而且由于没有项目从一个数组移出另一个数组的概念,因此您应该摆脱动画问题及其涉及的其他复杂性。
注意:
与“显示更多/更少”按钮相关的代码只是经过简化以表达想法。请相应地更改代码。
希望有帮助。