angular2滚动到底部(聊天风格)

Max*_*der 98 scroll typescript angular

我在ng-for循环中有一组单细胞组件.我已经掌握了一切,但我似乎无法找到合适的东西

目前我有一个

setTimeout(() => {
  scrollToBottom();
});
Run Code Online (Sandbox Code Playgroud)

但是这不会一直有效,因为图像会异步地向下推动视口.

什么是在angular2中滚动到聊天窗口底部的适当方法?

let*_*hat 171

我有同样的问题,我正在使用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) { }                 
    }
}
Run Code Online (Sandbox Code Playgroud)

模板:

<div #scrollMe style="overflow: scroll; height: xyz;">
    <div class="..." 
        *ngFor="..."
        ...>  
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

当然这是非常基本的.在AfterViewChecked每次有人检查时间触发器:

实现此接口以在每次检查组件视图后收到通知.

例如,如果你有一个用于发送消息的输入字段,那么在每个keyup之后会触发这个事件(仅举一个例子).但是,如果你保存用户是否手动滚动然后跳过scrollToBottom()你应该没问题.

  • http://plnkr.co/edit/7yz2DUttPjI5GVJkvr5h?open=app%2Fapp.component.ts&p=info (4认同)
  • 嗨,有没有办法防止用户向上滚动? (2认同)
  • 我也试图在聊天风格的方法中使用它,但如果用户向上滚动,则不需要滚动。我一直在寻找,但找不到检测用户是否向上滚动的方法。需要注意的是,这个聊天组件大部分时间都不是全屏的,并且有自己的滚动条。 (2认同)
  • @HarvP和JohnLouieDelaCruz是否找到了一种解决方案,如果用户手动滚动,则可以跳过滚动? (2认同)

Viv*_*shi 137

最简单,最好的解决方案是:

#scrollMe [scrollTop]="scrollMe.scrollHeight"Template端添加这个简单的东西

<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
    <div class="..." 
        *ngFor="..."
        ...>  
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这是工作演示(使用虚拟聊天应用程序)和完整代码的链接

将与Angular2一起使用,也可以使用5,如上面的演示在Angular5中完成.


注意 :

出错: ExpressionChangedAfterItHasBeenCheckedError

请检查你的CSS,这是css方面的问题,而不是Angular方面,用户之一@KHAN通过删除overflow:auto; height: 100%;来解决了这个问题div.(请查看对话详情)

  • 你怎么触发滚动? (3认同)
  • 它将自动滚动到添加到ngfor项目的任何项目的底部或当内侧div的高度增加时 (3认同)
  • @csharpnewbie当从列表中删除任何消息时,我也遇到同样的问题:`在检查表达式后,表达式已更改。上一个值:'scrollTop:1758'。当前值:'scrollTop:1734'`。解决了吗 (3认同)
  • 通过向[scrollTop]添加条件,我能够解决"表达式在检查后发生了变化"(同时保持高度:100%;溢出y:滚动),以防止它被设置直到我有数据填充它用,例如:<ul class ="chat-history"#chatHistory [scrollTop] ="messages.length === 0?0:chatHistory.scrollHeight"> <li*ngFor ="let message of messages"> ..添加"messages.length === 0?0"检查似乎解决了问题,虽然我无法解释原因,所以我不能肯定地说这个修复并不是我的实现所特有的. (3认同)
  • 谢谢@VivekDoshi。虽然在添加了一些东西之后我得到了这个错误:&gt;ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it is checked. 以前的值:'700'。当前值:'517'。 (2认同)
  • 我找到了问题,类example-scrolling-content我有这些css类.溢出:自动; 身高:100%; 一旦我从div中删除了这个类就可以了. (2认同)
  • 这应该是公认的答案!正在研究角度 8 (2认同)
  • 很好的解决方案,但我一直遇到错误“表达式在检查后已更改”,将更改检测策略更改为“changeDetection:ChangeDetectionStrategy.OnPush”为我解决了问题 (2认同)

rob*_*ing 18

我添加了一个检查以查看用户是否尝试向上滚动.

如果有人想要的话我就打算离开这里:)

<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>
Run Code Online (Sandbox Code Playgroud)

和代码:

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

}
Run Code Online (Sandbox Code Playgroud)


Bor*_*hik 17

考虑使用

.scrollIntoView()
Run Code Online (Sandbox Code Playgroud)

请参阅https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

  • @chavocarlos - 似乎除了 Opera Mini 之外的所有东西都支持:https://caniuse.com/#feat=scrollintoview (2认同)

den*_*try 13

这些答案都没有一半是正确的.滚动浏览消息时会触发接受的答案.

你想要一个像这样的模板.

<div #content>
  <div #messages *ngFor="let message of messages">
    {{message}}
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

然后,您希望使用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) {}
}
Run Code Online (Sandbox Code Playgroud)

  • 迄今为止最好的答案。谢谢 ! (2认同)
  • 惊人的!!!我使用了上面的那个,觉得它很棒,但后来我陷入了向下滚动的困境,我的用户无法阅读以前的评论!感谢您提供这个解决方案!极好的!如果可以的话我会给你100+分:-D (2认同)

Mer*_*ert 9

如果你想确定,在完成*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;
}
Run Code Online (Sandbox Code Playgroud)

重要的是,"last"变量定义您当前是否在最后一项,因此您可以触发"scrollToBottom"方法

  • 这个答案值得被接受。这是唯一有效的解决方案。Denixtry 的解决方案由于 Angular 错误而不起作用,其中 QueryList 更改订阅仅触发一次,即使在 ngAfterViewInit 中声明也是如此。无论添加什么元素,Vivek 的解决方案都会触发,而 Mert 的解决方案仅在添加某些元素时才会触发。 (2认同)

Ret*_*ent 9

如果您使用的是最新版本的 Angular,以下内容就足够了:

<div #scrollMe style="overflow: scroll; height: xyz;" [scrollTop]="scrollMe.scrollHeight>
    <div class="..." 
        *ngFor="..."
        ...>  
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 对于大多数情况来说这很简单:) (2认同)

小智 6

this.contentList.nativeElement.scrollTo({left: 0 , top: this.contentList.nativeElement.scrollHeight, behavior: 'smooth'});
Run Code Online (Sandbox Code Playgroud)

  • 使提问者朝正确方向前进的任何答案都是有帮助的,但请尝试在答案中提及任何限制,假设或简化。简短是可以接受的,但更充分的解释会更好。 (4认同)

小智 6

const element = document.getElementById('box');
element.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' });
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

124675 次

最近记录:

6 年,3 月 前