将项目添加到 DOM 时的 Chrome 滚动行为

Arn*_*lle 5 javascript google-chrome typescript angular

我正在实施无限滚动以显示按日期分组的操作。当用户到达页面底部时,我加载下一个操作。

因此,在滚动一点后,用户将看到:

-------------------------------------------
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
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

到达底部时,将加载新操作。预期的行为是这样的:

-------------------------------------------
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
 -------------------------------------------
Run Code Online (Sandbox Code Playgroud)

加载对用户是透明的。滚动可以无缝继续。仅在 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
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

Chrome 似乎会自动滚动以保持最后一个元素可见(这里是页面底部)。这会导致无限加载下一个操作。

数据是一张地图{[key: string]: Operation[]},其中keyadate表示为string

我是这样渲染的:

-------------------------------------------
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
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

:是否有我可以调用的 javascript 函数来停用此行为?

我准备了一个StackBlitz来重现这个问题。请在 Chrome 中尝试。

场景

  • 单击“向地图添加类别”10 次
  • 滚动到页面底部
  • 在“向地图添加类别”上再次单击 3 次
  • 页面底部保持可见。不应该。

奇怪的是,如果我使用一个简单的列表,我不会重现这个问题 *ngFor(您可以使用另一个按钮进行测试:“将项目添加到列表中”)

另外,如果我删除“页面底部”元素,我也没有问题。我想在这种情况下,Chrome 将关注列表的最后一个元素。

Chr*_*isM 1

据我所知,没有一种简单的方法可以禁用此行为。我认为 Chrome 试图保持屏幕上的内容静态并避免“屏幕跳转”。在许多情况下这是可取的,但在本例中显然不是这样。

解决方法是在动态加载内容的底部和页面底部元素之间使用间隔元素。该垫片的高度已调整,以准备加载动态加载的内容,这有效地为要加载的新内容创建了一个空间,并将视口从内容的底部移开,从而停止了您正在观察的行为。

你可以在我的stackblitz分支中看到这个概念的粗略证明。

这里是代码的关键部分供参考。

应用程序组件.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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

应用程序组件.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>
Run Code Online (Sandbox Code Playgroud)

并且您添加height:100px;或类似的loadingSpacer.

在这里,我结合了承诺和人为延迟来模拟加载。以同步方式做这样的事情可能也可能不可能,但由于它涉及两个操作(扩展高度,加载内容),需要以特定的顺序反映在 DOM / 页面状态中,我的感觉是它本质上是异步的。

我首先考虑使用类似window.scrollByCSS 和 HTML 的东西,这似乎是一个更明显的解决方案。然而,我发现使用它会很棘手,同时避免难看的屏幕跳转或依赖于提前知道内容的高度。

我并不是 100% 确定为什么这会起作用,因为这是一个纯粹的实验,基于“是否有某种方法可以使用 CSS 强制向上滚动”的想法。需要做一些技巧,并且有一些技术和设计限制,但至少应该给你一些可以使用的东西。