typescript - Angular 2 Posunúť na spodok (štýl chatu)
Mám sadu komponentov jednotlivých buniek v slučke ng-for.
Mám všetko pripravené, ale nedokážem prísť na správne
Momentálne mám
setTimeout(() => {
scrollToBottom();
});
Ale toto nefunguje vždy, pretože obrázky asynchrónne posúvajú zobrazenie nadol.
Aký je vhodný spôsob, ako sa posunúť na spodok chatovacieho okna v Angular 2?
Odpoveď č. 1
Mal som rovnaký problém, používam kombináciu AfterViewChecked a @ViewChild (Angular2 beta.3).
Komponent:
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) { }
}
}
Šablóna:
<div #scrollMe style="overflow: scroll; height: xyz;">
<div class="..."
*ngFor="..."
...>
</div>
</div>
Samozrejme, toto je dosť základné. AfterViewChecked sa spustí zakaždým, keď bola kontrolovaná zobrazovaná časť:
Implementujte toto rozhranie, aby ste boli informovaní po každej kontrole pohľadu vášho komponentu.
Ak máte napríklad vstupné pole na odosielanie správ, táto udalosť sa spustí po každom uvoľnení klávesu (len ako príklad). Ale ak uložíte, či používateľ roloval manuálne a potom preskočíte scrollToBottom(), mali by ste byť v poriadku.
Odpoveď č. 2
Najjednoduchšie a najlepšie riešenie pre toto je :
Pridajte túto #scrollMe [scrollTop]="scrollMe.scrollHeight" jednoduchú vec na stranu šablóny
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
Tu je odkaz na FUNGUJÚCU DEMO VERZIU (s ukážkovou chatovou aplikáciou) A ÚPLNÝ KÓD
Bude pracovať s Angular2 a tiež až po 5, ako vyššie uvedená ukážka je urobená v Angular5.
Poznámka:
Pre chybu:
ExpressionChangedAfterItHasBeenCheckedErrorSkontrolujte prosím svoj CSS, je to problém na strane CSS, nie na strane Angularu. Jeden z používateľov @KHAN to vyriešil odstránením
overflow:auto; height: 100%;zdiv. (podrobnosti nájdete v konverzáciách)
Odpoveď č. 3
Prijatá odpoveď sa spúšťa pri rolovaní správ, toto tomu zabraňuje.
Chceš šablónu ako túto.
<div #content>
<div #messages *ngFor="let message of messages">
{{message}}
</div>
</div>
Potom chcete použiť anotáciu ViewChildren na prihlásenie sa na odber nových prvkov správ, ktoré sa pridávajú na stránku.
@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) {}
}
Odpoveď č. 4
Pridal som kontrolu, aby som zistil, či sa používateľ pokúsil rolovať nahor.
Len to tu nechám, akby to niekto chcel :)
<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>
a kód:
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) { }
}
}
Odpoveď č. 5
Ak chcete mať istotu, že budete posúvať na koniec po dokončení *ngFor, môžete použiť toto.
<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;
}
Dôležité je, že premenná "last" určuje, či sa nachádzate pri poslednej položke, takže môžete spustiť metódu "scrollToBottom"
Odpoveď č. 6
Zvážte použitie
.scrollIntoView()
Pozrite si https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Odpoveď č. 7
Ak používate novú verziu Angularu, nasledujúce je postačujúce:
<div #scrollMe style="overflow: scroll; height: xyz;" [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
