我正在实现无限滚动,以便显示按日期分组的操作。当用户到达页面底部时,我将加载下一个操作。
因此,在稍微滚动之后,用户将看到以下内容:
-------------------------------------------
May, 23rd
Operation 11
Operation 12 This zone is visible
Operation 13 by the user
Operation 14
Operation 15
page bottom
-------------------------------------------
this zone is outside
of the viewport
-------------------------------------------
到达底部时,将加载新操作。预期的行为是这样的:
-------------------------------------------
May, 23rd
Operation 11
Operation 12 This zone is visible
Operation 13 by the user
Operation 14
Operation 15
-------------------------------------------
Operation 16
Operation 17
Operation 18 this zone is outside
Operation 19 of the viewport
Operation 20
page bottom
-------------------------------------------
加载对用户是透明的。滚动可以无缝继续。 仅在Chrome中的实际行为是:
-------------------------------------------
Operation 16
Operation 17
Operation 18 This zone is visible
Operation 19 by the user
Operation 20
page bottom
-------------------------------------------
this zone is outside
of the viewport
-------------------------------------------
Chrome似乎会自动滚动以使最后一个元素可见(此处位于页面底部)。这将导致无限次加载下一个操作。
数据是地图{[key: string]: Operation[]}
,其中key
是表示为date
的{{1}}。
我这样渲染它:
string
问题:是否可以调用一个javascript函数来停用此行为?
我准备了StackBlitz来重现该问题。请在Chrome中尝试。
场景:
奇怪的是,如果我使用带有<section *ngFor="let entry of accountOperations | keyvalue:descOrder">
<h3>{{entry.key}}</h3>
<ul>
<li *ngFor="let operation of entry.value">
<app-operation [operation]="operation">
</app-operation>
</li>
</ul>
</section>
的简单列表(可以用另一个按钮进行测试:“将项目添加到列表”),则不会重现该问题
此外,如果删除“页面底部”元素,也不会出现问题。我想在这种情况下,Chrome会专注于列表的最后一个元素。
答案 0 :(得分:3)
有关child元素的一些CSS为我解决了此问题。
就我而言:
.load-more{
overflow-anchor: none;
}
答案 1 :(得分:1)
据我所知,没有一种简单的方法可以禁用此行为。我认为Chrome浏览器正在尝试使屏幕上的内容保持静态,并避免“屏幕跳动”。在许多情况下,这是可取的,但是显然在这种情况下不是。
一种解决方法是在动态加载的内容底部和页面底部元素之间使用spacer元素。该间隔物的高度已调整,可以为动态加载的内容加载做准备,这有效地为新内容创建了加载空间,并使视口远离内容底部,从而停止了您正在观察的行为。
您可以在我的stackblitz的分支中看到这一概念的粗略证明。
这里是供参考的代码的关键部分。
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
counter = 1;
itemCounter = 1;
loading = false;
categories: { [key: string]: string[] } = {
'category 1': ['A1', 'A2', 'A3']
}
items: string[] = [];
addCategory() {
this.loading = true;
this.fetchCategory().then((category : string[]) =>{
this.categories['category ' + this.counter++] = category;
this.loading = false;
})
}
addItem() {
this.items.push('Item ' + this.itemCounter++);
}
fetchCategory() {
return new Promise((resolve, reject) =>{
window.setTimeout(()=>{
resolve(['A1','A2','A3']);
this.loading = false;
}, 300);
});
}
descOrder = (a, b) => {
if (+a.key.substring(9) < +b.key.substring(9)) {
return b.key;
}
}
}
app.component.html
<button id="btn-add-category" (click)="addCategory()">Add a category to the map</button>
<button id="btn-add-item" (click)="addItem()">Add an item to the list</button>
<section *ngFor="let cat of categories | keyvalue:descOrder">
{{cat.key}}
<ul>
<li *ngFor="let val of cat.value">{{val}}</li>
</ul>
</section>
<ul>
<li *ngFor="let item of items">
<h3>{{ item }}</h3>
</li>
</ul>
<div *ngIf="loading" class="loadingSpacer"></div>
<h1 id="page-bottom">Page bottom</h1>
然后您添加height:100px;
或类似的loadingSpacer
。
在这里,我合并了一个promise和一个人为的延迟来模拟加载。可能无法同步执行这样的操作,但是由于它涉及到两个操作(扩展高度,加载内容),这些操作需要以特定顺序反映在DOM /页面状态中,我的感觉是它本质上是异步的。
我首先考虑使用window.scrollBy
之类的东西代替CSS和HTML,这似乎是一个更明显的解决方案。但是,我发现在使用此功能的同时避免避免难看的屏幕跳动或依赖于事先知道内容的高度会很棘手。
我不确定100%为何在这一点上可行,因为这是一个纯粹的实验,基于“有某种方法可以强制使用CSS向上滚动”的思想。会有一些麻烦的事情,并且在技术和设计上都有局限性,但至少应该给您一些帮助。