[scroll] Angular 2 아래로 스크롤 (채팅 스타일)

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) {}
}


답변


답변

* 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'});