设置nativeElement.scrollTop无效,无法滚动到div底部

4

I have this code in angular application

html:

<input type="button" value="Add" (click)="addItems()" />
<div id="messageContainer" style="width:200px; height:300px; overflow-y:scroll;" #scrollMe >
  <div *ngFor="let i of items">
    {{i}}
  </div>
</div>

component.ts:

items: string[] = [];
count = 20;

@ViewChild('scrollMe') private scrollContainer: ElementRef;

ngOnInit() {
    this.addInitialItems();
}

addItems() {
    const currentPosition = this.scrollContainer.nativeElement.scrollTop;

    this.items.unshift(this.count.toString());
    this.count++;

    this.scrollContainer.nativeElement.scrollTop = currentPosition;
 }

addInitialItems() {
    for (let i = 0; i <= this.count - 1; i++) {
        this.items.unshift(i.toString());
    }

    // this is not working
    this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight; 
}

初始时,messageContainer div 应该填充多个项目,并将 div 滚动到底部。当用户点击“添加”按钮时,它将在消息列表顶部添加一个项目,并应保持滚动位置。

保留滚动位置可通过以下方式实现:

const currentPosition = this.scrollContainer.nativeElement.scrollTop;
//add new item
this.scrollContainer.nativeElement.scrollTop = currentPosition;

但是,最初滚动到 div 底部的功能不起作用。

this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;

即使已经设置了scrollTop的值,它仍为0,如何将其初始滚动到

的底部?

2个回答

10

@ViewChild对象在'ngAfterViewInit'生命周期钩子之前并未完全定义。请尝试将您的方法调用移至该钩子。

ngAfterViewInit() {
   this.addInitialItems();
}

你可能想尝试的另一种方法是直接在模板中绑定scrollTop,这样你就不必完全访问nativeElement了。

<input type="button" value="Add" (click)="addItems()" />
<div id="messageContainer" style="width:200px; height:300px; overflow-y:scroll;"  [scrollTop]="myScrollVariable">
  <div *ngFor="let i of items">
    {{i}}
  </div>
</div>

在您的组件中,您可以简单地编写类似以下内容的代码:
this.myScrollVariable = currentPosition;

不要直接修改DOM元素。虽然如果你想将滚动条初始化为scrollHeight的话,可能仍需要使用ViewChild来访问nativeElement并获取该属性(尽管个人而言,我会将scrollTop初始化为一个荒谬地大的数字,比如99999999,任何大于scrollHeight的数字都与确切的scrollHeight相同)。

如果将方法调用移动到ngAfterViewInit中无法解决问题,请尝试在setTimeout函数内设置scrollTop。有时候Angular变化检测器会奇怪地无法捕捉到对本地DOM的更改,因此你可以通过timeout逃离常规的Angular事件循环来避免这种情况。

setTimeout(()=>{ this.scrollContainer.nativeElement.scrollTop = whatever; },1)

2
不需要使用setTimeout。只需在ngAfterViewInit中设置scrollTop的部分即可。将初始模型值设置在ngOnInit / constructor中进行。https://stackblitz.com/edit/angular-5pm6ks?file=src/app/app.component.ts - Shantanu
你很有可能是对的,但在Angular中,某些DOM属性/方法非常棘手,偶尔我不得不将它们放入超时中,以便它们可以一致地改变(例如.focus())。 - diopside

0

在已接受的答案基础上,您可以使用模板变量相当优雅地将 div 设置为从底部开始滚动:

<div class="overflow-scroll" #scrollContainer [scrollTop]="scrollContainer.scrollHeight">
<!-- tall/wide content -->
</div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接