typescript - Angular 2 滾動到底部(聊天樣式)
我在一個 ng-for 迴圈中有一組單一元件。
我已經把一切都準備就緒,但我似乎無法弄清楚正確的方式
目前我有
setTimeout(() => {
scrollToBottom();
});
但這並不總是有效,因為圖片會非同步地將視口向下推動。
在 Angular 2 中,滾動到聊天視窗底部的適當方式是什麼?
答案#1
我有同樣的問題,我正在使用 AfterViewChecked 和 @ViewChild 的組合(Angular2 beta.3)。
元件:
import {..., AfterViewChecked, ElementRef, ViewChild, OnInit} from 'angular2/core'
@Component({
...
})
export class ChannelComponent implements OnInit, AfterViewChecked {
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
ngOnInit() {
this.scrollToBottom();
}
ngAfterViewChecked() {
this.scrollToBottom();
}
scrollToBottom(): void {
try {
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
}
範本:
<div #scrollMe style="overflow: scroll; height: xyz;">
<div class="..."
*ngFor="..."
...>
</div>
</div>
當然,這相當基礎。AfterViewChecked 每次視圖被檢查時都會觸發:
實作此介面以在每次檢查您的元件視圖後收到通知。
例如,如果你有一個用於發送消息的輸入欄位,這個事件會在每次按鍵彈起後觸發(僅舉例)。但是,如果你保存用戶是否手動滾動,然後跳過 scrollToBottom(),應該就沒問題。
答案#2
這個最簡單且最好的解決方案是:
在 模板端 添加這個 #scrollMe [scrollTop]="scrollMe.scrollHeight" 簡單的東西
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
這裡是 運行示範(帶虛擬聊天應用程式)以及 完整程式碼 的連結
將適用於 Angular2 以及最高到 Angular5,如上所示的範例是使用 Angular5 完成的。
注意:
錯誤:
ExpressionChangedAfterItHasBeenCheckedError請檢查你的 CSS,這是 CSS 端的問題,而不是 Angular 端的問題。其中一位用戶 @KHAN 已經通過從
div中移除overflow:auto; height: 100%;解決了這個問題。(詳細請查看對話內容)
答案#3
接受的答案會在滾動訊息時觸發,這可以避免那種情況。
你想要一個像這樣的模板。
<div #content>
<div #messages *ngFor="let message of messages">
{{message}}
</div>
</div>
然後你想使用 ViewChildren 註解來訂閱新增到頁面的訊息元素。
@ViewChildren('messages') messages: QueryList<any>;
@ViewChild('content') content: ElementRef;
ngAfterViewInit() {
this.scrollToBottom();
this.messages.changes.subscribe(this.scrollToBottom);
}
scrollToBottom = () => {
try {
this.content.nativeElement.scrollTop = this.content.nativeElement.scrollHeight;
} catch (err) {}
}
答案#4
我添加了一個檢查,以查看使用者是否嘗試向上滾動。
我就把這個放在這裡,如果有人想要的話 :)
<div class="jumbotron">
<div class="messages-box" #scrollMe (scroll)="onScroll()">
<app-message [message]="message" [userId]="profile.userId" *ngFor="let message of messages.slice().reverse()"></app-message>
</div>
<textarea [(ngModel)]="newMessage" (keyup.enter)="submitMessage()"></textarea>
</div>
以及程式碼:
import { AfterViewChecked, ElementRef, ViewChild, Component, OnInit } from '@angular/core';
import {AuthService} from "../auth.service";
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/concatAll';
import {Observable} from 'rxjs/Rx';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.scss']
})
export class MessagesComponent implements OnInit {
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
messages:Array<MessageModel>
newMessage = ''
id = ''
conversations: Array<ConversationModel>
profile: ViewMyProfileModel
disableScrollDown = false
constructor(private authService:AuthService,
private route:ActivatedRoute,
private router:Router,
private conversationsApi:ConversationsApi) {
}
ngOnInit() {
}
public submitMessage() {
}
ngAfterViewChecked() {
this.scrollToBottom();
}
private onScroll() {
let element = this.myScrollContainer.nativeElement
let atBottom = element.scrollHeight - element.scrollTop === element.clientHeight
if (this.disableScrollDown && atBottom) {
this.disableScrollDown = false
} else {
this.disableScrollDown = true
}
}
private scrollToBottom(): void {
if (this.disableScrollDown) {
return
}
try {
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
}
答案#5
如果你想確保在 *ngFor 完成後,你正在滾動到結尾,你可以使用這個。
<div #myList>
<div *ngFor="let item of items; let last = last">
{{item.title}}
{{last ? scrollToBottom() : ''}}
</div>
</div>
scrollToBottom() {
this.myList.nativeElement.scrollTop = this.myList.nativeElement.scrollHeight;
}
重要的是,這裡的 "last" 變數用於定義你是否目前在最後一個項目,因此你可以觸發 "scrollToBottom" 方法
答案#6
考慮使用
.scrollIntoView()
請參見 https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
答案#7
如果你使用的是較新的 Angular 版本,以下就足夠了:
<div #scrollMe style="overflow: scroll; height: xyz;" [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
