Javascript ionic 2 + angular 2:自动滚动到列表/页面/聊天的底部

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37415085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:18:26  来源:igfitidea点击:

ionic 2 + angular 2 : auto scroll to bottom of list / page / chat

javascriptangularchationic2autoscroll

提问by sandrina-p

I'm trying to code a page with two segments "chat" and "content". I want that one "chat" segment the page auto-scroll to the bottom with no effect. The chat is a <ion-list>with several <ion-item>.

我正在尝试编写一个包含“聊天”和“内容”两个部分的页面。我希望一个“聊天”段将页面自动滚动到底部而没有任何效果。聊天是一个<ion-list>与几个<ion-item>

<ion-list>
<ion-item> item 1 </ion-item>
<ion-item> item 2 </ion-item>
....
<ion-item> item 20 </ion-item>
<ion-item> item 21 </ion-item> <!-- user should see directly this item on bottom of the page -->
</ion-list>

I'm using Javascript, not typescript, and I don't wan't to use jQuery. Thanks :) Plus, when I go to "content" segment and go back to "chat" I want to auto-scroll again the chat.

我使用的是 Javascript,而不是打字稿,而且我不想使用 jQuery。谢谢:) 另外,当我转到“内容”部分并返回“聊天”时,我想再次自动滚动聊天。

采纳答案by sandrina-p

First off all, @rinukkusu answer is right but it doesn't work on my case because <ion-content>(parent of <ion-list>) has some bugs with it (ionic developers are working on that), so I had to put that element with scroll:hiddenand create a second content inside to apply the auto-scroll. Finally with the right (s)css I called the function on construtorwhen the page loads and then each time the users clicks on "chat" segment.

首先,@rinukkusu 的答案是正确的,但它不适用于我的情况,因为<ion-content>(的父级<ion-list>)有一些错误(离子开发人员正在处理),所以我不得不放置该元素scroll:hidden并创建第二个内容在里面应用自动滚动。最后,使用正确的 (s)css,我construtor在页面加载时调用该函数,然后每次用户单击“聊天”段时调用该函数。

chat.html

聊天.html

<!-- I create the segment and call the `autoScroll()` when users clicks on "chat" -->
<ion-toolbar primary class="toolbar-segment">
    <ion-segment light [(ngModel)]="segment">
        <ion-segment-button value="chat" (click)="autoScroll()">
            Chat
        </ion-segment-button>
        <ion-segment-button value="profile">
            Profile
        </ion-segment-button>
    </ion-segment>
</ion-toolbar>

<!--I wrote the css inline just as example. 
  DON'T do it on your project D: -->

<!-- overflow:hidden prevent the ion-content to scroll -->
<ion-content [ngSwitch]="segment" style="overflow: hidden;">

    <!-- height: 100% to force scroll if the content overflows the container.
         #chat-autoscroll is used by javascript.-->
    <div class="content-scroll" id="chat-autoscroll" *ngSwitchWhen="'chat'" style="height: 100%; overflow: scroll">
        (... make sure the content is bigger 
        than the container to see the auto scroll effect ...)
    </div>

    <!-- here it's just a normal scroll  -->
    <div *ngSwitchWhen="'profile'" class="content-scroll" style="height: 100%; overflow: auto">
      (... content of profile segment ...)
    </div>

</ion-content>

chat.js

聊天.js

constructor () {

    // when the user opens the page, it shows the "chat" segment as initial value
    this.segment = 'chat'; 

    // when page loads, it calls autoScroll();
    if (this.segment == 'chat') {
        console.log('chat');
        this.autoScroll();
    };
}

/*Here comes the tricky. 
 If you don't use setTimeout, the console will say that
 #chat-autoscroll doesn't exist in the first call (inside constructor). 
 This happens because the script runs before the DOM is ready. 
 I did a workaround with a timeOut of 10ms.
 It's enough time to DOM loads and then autoScroll() works fine.
*/
autoScroll() {
    setTimeout(function () {
        var itemList = document.getElementById("chat-autoscroll");
        itemList.scrollTop = itemList.scrollHeight;
    }, 10);
}

Conclusion:The function is called twice. When the page is loaded (constructor) and each time the user comes back to "chat" segment. (click)="autoScroll()"

结论:该函数被调用了两次。当页面被加载(构造函数)并且每次用户回到“聊天”段时。(点击)=“自动滚动()”

I hope this helps someone. If you know better way, let me know! I started playing with Angular2 and Ionic2 a couple of weeks ago so there is a lot of concepts/bases that I might be missing here.

我希望这可以帮助别人。如果你知道更好的方法,请告诉我!几周前我开始使用 Angular2 和 Ionic2,所以我可能在这里遗漏了很多概念/基础。

Thanks :)

谢谢 :)

回答by smukov

Here's how I did it:

这是我如何做到的:

chatPage.html

聊天页面.html

<ion-content #content padding class="chatPage">

  <ion-list no-lines>
    <ion-item *ngFor="let msg of messages" >
      <chat-bubble [message]="msg"></chat-bubble>
    </ion-item>
  </ion-list>

</ion-content>

The important bit in chatPage.htmlis #contenton <ion-content>. I'll use the #contentidentifier to obtain a reference to <ion-content>in my chatPage.jsusing the ViewChild.

chatPage.html 中的重要部分#content<ion-content>。我将使用#content标识符<ion-content>在我的chatPage.js 中使用ViewChild.

Now for the actual scrolling logic:

现在是实际的滚动逻辑:

chatPage.js

聊天页面.js

import {Component, ViewChild} from '@angular/core';

@Component({
  templateUrl: 'build/pages/chatPage/chatPage.html',
  queries: {
    content: new ViewChild('content')
  }
})
export class ChatPage {
  constructor() { 

  }

  //scrolls to bottom whenever the page has loaded
  ionViewDidEnter(){
    this.content.scrollToBottom(300);//300ms animation speed
  }
}

Also, whenever my chatPageneeds to show another chat message in the list (either a new message is received, or a new message is sent), I'm using the below code to scroll to the new bottom:

此外,每当我的chatPage需要在列表中显示另一条聊天消息(收到新消息或发送新消息)时,我都会使用以下代码滚动到新底部:

setTimeout(() => {
  this.content.scrollToBottom(300);//300ms animation speed
});


Update for Typescript

更新打字稿

Back when I gave this answer I was working with JavaScript version of Ionic 2 project. Over time I switched to TypeScript but I forgot to update the answer, so, here's a small update for chatPage.js(ts):

当我给出这个答案时,我正在使用 Ionic 2 项目的 JavaScript 版本。随着时间的推移,我切换到 TypeScript,但我忘记更新答案,因此,这是chatPage.js(ts)的一个小更新:

chatPage.ts

聊天页面.ts

import {Component, ViewChild} from '@angular/core';

@Component({
  templateUrl: 'chatPage.html'
})
export class ChatPage {
  @ViewChild('content') content:any;

  constructor() { }

  //scrolls to bottom whenever the page has loaded
  ionViewDidEnter(){
    this.content.scrollToBottom(300);//300ms animation speed
  }
}

回答by itsme_seenu

The Ionic has an option to do this and works pretty good: And this is the most appropriate way with angular 2+ and Ionic.

Ionic 有一个选项可以做到这一点并且效果很好:这是 angular 2+ 和 Ionic 最合适的方式。

import { Content } from ‘ionic-angular';

export class CommentsPage{
@ViewChild(Content) content: Content;

    ionViewWillEnter(): void {
        this.scrollToBottom();
    }

    scrollToBottom() {
        setTimeout(() => {
            this.content.scrollToBottom();
        });
    }
}

回答by Sujit Kumar Singh

This could help someone, I have given similar answer in Ionic forum. This is implemented in Ionic 3.

这可以帮助某人,我在 Ionic 论坛中给出了类似的答案。这是在 Ionic 3 中实现的。

I used ngAfterViewChecked()to achieve this feature. Following is my code structure -

我曾经ngAfterViewChecked()实现过这个功能。以下是我的代码结构 -

home.html -

主页.html -

<ion-content padding>
    <div #scrollMe id="messages-container" style="overflow: auto; height: 100%;">
        // All messages elemets. Scroll
    </div>
</ion-content>

home.ts -

home.ts -

import { Component,ViewChild, AfterViewChecked, * * } from '@angular/core';
.
.
export class HomePage implements AfterViewChecked{
    // used for scrolling the pane
    @ViewChild('scrollMe') private myScrollContainer: ElementRef;

    ngAfterViewChecked() {
        this.scrollToBottom();
    }

    scrollToBottom(): void {
        // method used to enable scrolling
        this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
    }
}

.scrollTopand .scrollHeightare JavaScript properties, see here.

.scrollTop.scrollHeight是 JavaScript 属性,请参见此处

回答by Saravanan Nandhan

I added a check to see if the user tried to scroll up.

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

<div style="overflow: scroll; height: xyz;" #scrollMe [scrollTop]="scrollMe.scrollHeight">
    <div class="..." 
        *ngFor="..."
        ...>  
    </div>
</div>

回答by Gianfranco P.

Another solution is to "observe" changes in the scroll view and scroll automatically. i.e. if there are new HTML elements where the messages appear then scroll to the bottom.

另一种解决方案是“观察”滚动视图中的变化并自动滚动。即,如果出现消息的地方有新的 HTML 元素,则滚动到底部。

export class MessagesPage implements OnInit, OnDestroy {
  autoScroller: MutationObserver;

  ngOnInit() {
    this.autoScroller = this.autoScroll();
  }

  ngOnDestroy() {
    this.autoScroller.disconnect();
  }

  autoScroll(): MutationObserver {
    const autoScroller = new MutationObserver(this.scrollDown.bind(this));

    autoScroller.observe(this.messagesList, {
      childList: true,
      subtree: true
    });

    return autoScroller;
  }

  scrollDown(): void {
    this.scroller.scrollTop = this.scroller.scrollHeight;
    this.messageEditor.focus();
  }

  private get messageEditor(): HTMLInputElement {
    return <HTMLInputElement>document.querySelector('ion-input');
  }

  private get messagesList(): Element {
    return document.querySelector('.messages');
  }

  private get scroller(): Element {
    return this.messagesList.querySelector('.scroll-content');
  }
}

Template:

模板:

<ion-content>
  <ion-scroll scrollY="true" class="messages">
    <ion-list>
      <div *ngFor="let message of messages">
        <p [innerHtml]="message.text"></p>
      </div>
    </ion-list>
  </ion-scroll>
</ion-content>

<ion-footer>
  <ion-toolbar>
    <ion-input [(ngModel)]="message" type="text" placeholder="Write a message..." autocomplete="true" spellcheck="true" tappable></ion-input>
    <ion-buttons end>
      <button ion-button icon-only (click)="sendMessage()">
        <ion-icon name="paper-plane"></ion-icon>
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-footer>

(take from Ionic2CLI-Meteor-WhatsApp on Github)

(取自Github 上的 Ionic2CLI-Meteor-WhatsApp

回答by Collaborator

This is my solution with Ionic CLI 5.4.16 :

这是我使用 Ionic CLI 5.4.16 的解决方案:

In page HTML:

在页面 HTML 中:

<ion-content #content>

In page .TS:

在页面 .TS 中:

@ViewChild('content', { static: true }) content: any;



 constructor(){}

  getInformation(){

//Your Code 

..........

//At the end

  **this.content.scrollToBottom();**

  }

回答by user2439674

Just do it:

去做就对了:

public ionViewDidEnter(){
    this.content.scrollToBottom(300);
}

回答by rinukkusu

This should work if your ion-listelement has a fixed height.

如果您的ion-list元素具有固定高度,这应该有效。

<ion-list id="item-list">
    <ion-item> item 1 </ion-item>
    <ion-item> item 2 </ion-item>
    [...]
    <ion-item> item 20 </ion-item>
    <ion-item> item 21 </ion-item>
</ion-list>

[...]

<script>
    var itemList = document.getElementById("item-list");
    itemList.scrollTop = itemList.scrollHeight
</script>