angular2 прокрутка вниз (стиль чата)
У меня есть набор компонентов одной ячейки в цикле ng-for.
У меня все на месте, но я не могу показаться, чтобы выяснить правильный
В настоящее время у меня есть
setTimeout(() => {
scrollToBottom();
});
но это не работает все время как изображения асинхронно нажимаем просмотра вниз.
каков подходящий способ прокрутки до нижней части окна чата в angular2?
8 ответов:
у меня была та же проблема, я использую
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>
вот ссылка РАБОЧАЯ ДЕМОНСТРАЦИЯ (С фиктивным приложением чата) и КОД
будет работать с Angular2, а также до 5, как показано выше демо делается в Angular5.
Примечание. :
ошибки :
ExpressionChangedAfterItHasBeenCheckedErrorпожалуйста, проверьте ваш css,это вопрос стороны css, а не угловой стороны , Один из пользователей @KHAN решил это, удалив
overflow:auto; height: 100%;Сdiv. (пожалуйста, проверьте разговоры для деталей)
рассмотрите возможность использования
.scrollIntoView()см.https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
я добавил проверку, чтобы увидеть, если пользователь попытался прокрутить вверх.
Я просто оставлю это здесь, если кому интересно :)
<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.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; }важно здесь "последнего" переменная определяет, если вы находитесь в данный момент на последнем элементе, так что вы можете вызвать "scrollToBottom" метод
this.contentList.nativeElement.scrollTo({left: 0 , top: this.contentList.nativeElement.scrollHeight, behavior: 'smooth'});
в угловом использовании material design sidenav мне пришлось использовать следующее:
let ele = document.getElementsByClassName('md-sidenav-content'); let eleArray = <Element[]>Array.prototype.slice.call(ele); eleArray.map( val => { val.scrollTop = val.scrollHeight; });
Comments