ng-for
루프 내에 단일 셀 구성 요소 집합이 있습니다.
모든 것이 제자리에 있지만 적절한 것을 파악할 수없는 것 같습니다.
현재 나는
setTimeout(() => {
scrollToBottom();
});
그러나 이미지가 비동기 적으로 뷰포트를 아래로 내리기 때문에 항상 작동하지는 않습니다.
Angular 2에서 채팅 창 하단으로 스크롤하는 적절한 방법은 무엇입니까?
답변
나는 똑같은 문제가 있었고 a 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()
괜찮을 것입니다.
답변
이를위한 가장 간단하고 최상의 솔루션은 다음과 같습니다.
이 #scrollMe [scrollTop]="scrollMe.scrollHeight"
간단한 것을 템플릿 측 에 추가하십시오.
<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
<div class="..."
*ngFor="..."
...>
</div>
</div>
다음은 WORKING DEMO (더미 채팅 앱 포함) 및 전체 코드 링크입니다.
Angular2 및 최대 5에서도 작동합니다. 위의 데모는 Angular5에서 수행됩니다.
노트 :
오류 :
ExpressionChangedAfterItHasBeenCheckedError
당신의 CSS를 확인하십시오, 그것은 CSS 측의 문제가 아닌 각도 측면, 사용자 @KHAN 중 하나는 제거하여 그것을 해결했다입니다
overflow:auto; height: 100%;
에서div
. (자세한 내용은 대화를 확인하십시오)
답변
사용자가 위로 스크롤을 시도했는지 확인하기 위해 확인을 추가했습니다.
누군가 원하면 여기에 남겨 둘 게요 🙂
<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) { }
}
}
답변
수락 된 답변은 메시지를 스크롤하는 동안 발생하므로이를 방지합니다.
이와 같은 템플릿이 필요합니다.
<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) {}
}
답변
사용 고려
.scrollIntoView()
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView를 참조 하십시오.
답변
* 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” 메서드를 트리거 할 수 있습니다.
답변
this.contentList.nativeElement.scrollTo({left: 0 , top: this.contentList.nativeElement.scrollHeight, behavior: 'smooth'});