【发布时间】:2021-08-25 16:03:06
【问题描述】:
我有一个可滚动的自我更新订单列表。这是父组件,其中列表在 2 分钟的计时器上更新,设置如下:
ngOnInit(): void {
this.internalError = false;
this.subscription = timer(0, 120 * 1000).pipe(
switchMap(() => this.shopService.getPreferencesAsObservable()),
filter(preferences => !!preferences), // emit only if `preferences` is defined and truthy
tap(() => {
this.isDeliverySlotsActive = this.shopService.isDeliverySlotsActive();
}),
switchMap(() =>
forkJoin([
this.getInitialPendingOrders(true),
this.getInitialPendingOrders(false),
this.getInitialDeliveredOrders(true),
this.getInitialDeliveredOrders(false),
this.getInitialCancelledOrders(true),
this.getInitialCancelledOrders(false)
]
)
)
).subscribe(res => {
/* pending slots */
this.loadedPendingSlotsOrders = [...res[0]["results"]];
this.pendingSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedPendingSlotsOrders, true);
/* pending no slots */
this.loadedPendingNoSlotsOrders = this.ordersService.filterOrders(res[1]["results"], OrderStatus.PENDING, false);
this.loadedProcessedNoSlotsOrders = this.ordersService.filterOrders(res[1]["results"], OrderStatus.PROCESSED, false);
this.loadedPendingNoSlotsOrders = [...this.loadedPendingNoSlotsOrders, ...this.loadedProcessedNoSlotsOrders];
this.pendingNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedPendingNoSlotsOrders, false);
/* delivered slots */
this.loadedDeliveredSlotsOrders = [...res[2]["results"]];
this.deliveredSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedDeliveredSlotsOrders, true);
/* delivered no slots */
this.loadedDeliveredNoSlotsOrders = this.ordersService.filterOrders(res[3]["results"], OrderStatus.DELIVERED, false);
this.deliveredNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedDeliveredNoSlotsOrders, false);
/* cancelled slots*/
this.loadedCancelledSlotsOrders = [...res[4]["results"]];
this.cancelledSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedCancelledSlotsOrders, true);
/* cancelled no slots */
this.loadedCancelledNoSlotsOrders = this.ordersService.filterOrders(res[5]["results"], OrderStatus.CANCELLED, false);
this.cancelledNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedCancelledNoSlotsOrders, false);
/* data is ready, we can stop showing spinner */
this.isLoaded = Promise.resolve(true);
});
}
getInitialPendingOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=PENDING&status=FULFILLED" + (hasSlots ? "&only_slots=true" : ''));
}
getInitialDeliveredOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=DELIVERED" + (hasSlots ? "&only_slots=true" : ''));
}
getInitialCancelledOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=CANCELLED" + (hasSlots ? "&only_slots=true" : ''));
}
另外,组件树如下:
OrdersComponent (prepare data to send to children) -> OrdersListComponent (*ngFor of sections) -> OrdersListSectionComponent (*ngFor of orders) -> OrdersListItemComponent (single order)
在这里您可以看到列表的外观(它是一个内部可滚动的 div):
可滚动div的css:
.scrollable {
min-height: 10vh;
max-height: 50vh;
overflow: auto;
background:
linear-gradient(white 33%, rgba(179,86,216, 0)),
linear-gradient(rgba(179,86,216, 0), white 66%) 0 100%,
radial-gradient(farthest-side at 50% 0, rgba(34,34,34, 0.5), rgba(0,0,0,0)),
radial-gradient(farthest-side at 50% 100%, rgba(34,34,34, 0.5), rgba(0,0,0,0)) 0 100%;
background-repeat: no-repeat;
background-attachment: local, local, scroll, scroll;
background-size: 100% 1.5rem, 100% 1.5rem, 100% 0.5rem, 100% 0.5rem;
scroll-behavior: smooth;
}
OrdersListSectionComponent 的模板:
<div *ngFor="let order of sectionOrders">
<app-orders-list-item
[order]="order"
[timeline]="timeline"
></app-orders-list-item>
<hr class="order-divider"/>
</div>
我遇到了这样一种情况,即当触发计时器时,此列表的滚动条会卡到顶部。这很糟糕,因为如果用户正在滚动列表,则滚动不应该回到顶部。
有谁知道我可以如何阻止这种不需要的滚动行为?
【问题讨论】:
-
如果你使用 ngFor 来迭代项目然后尝试添加 trackBy 函数
-
@Chellappanவ 请解释这将如何解决我的问题...
-
它不会重新创建已经渲染的项目。所以使用 trackby 可以解决这个问题。你试过了吗?
-
不幸的是没有工作。
-
首先,您订阅了无数次 - 在订阅中订阅。这是一种反模式,也是因为您无法控制正在发生的事情。在
filter()之后,您应该插入switchMap(() => this.shopService.getPreferencesAsObservable())并删除内部订阅。我建议您采用这种模式。最后,我们不知道getOrders里面是什么,所以很难知道是什么导致了返回顶部。
标签: html css angular typescript rxjs