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

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

我正在尝试对包含两个段 "chat" 和 "content" 的页面进行编码。我希望 "chat" 将页面自动滚动到底部,但没有任何效果。聊天是 <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>

我正在使用 Javascript,而不是 typescript,而且我不想使用 jQuery。 谢谢 :) 另外,当我转到 "content" 部分并返回 "chat" 时,我想再次自动滚动聊天。

如果您的 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>

首先,@rinukkusu 的回答是正确的,但它不适用于我的情况,因为 <ion-content><ion-list> 的父级)有一些错误(ionic 开发人员正在解决这个问题) ),因此我不得不将该元素与 scroll:hidden 一起放置,并在其中创建第二个内容以应用自动滚动。 最后,当页面加载时,我用正确的 (s)css 在 construtor 上调用了该函数,然后每次用户单击 "chat" 段时。

chat.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

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

结论: 该函数被调用两次。当页面加载(构造函数)时以及每次用户返回 "chat" 段时。 (点击)="autoScroll()"

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

谢谢 :)

我是这样做的:

chatPage.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>

chatPage.html 中的重要部分是 <ion-content> 上的 #content。我将使用 #content 标识符在我的 chatPage.js 中使用 ViewChild.[=19= 获取对 <ion-content> 的引用]

现在是实际的滚动逻辑:

chatPage.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
  }
}

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

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

Typescript 更新

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

的一个小更新

chatPage.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
  }
}

就去做吧:

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

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();
        });
    }
}

另一个解决方案是"observe"改变滚动视图并自动滚动。 即,如果消息出现的地方有新的 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');
  }
}

模板:

<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>

(取自Ionic2CLI-Meteor-WhatsApp on Github

这可能对某人有帮助,我已经给出了类似的答案in Ionic forum。这是在 Ionic 3 中实现的。

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

home.html -

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

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;
    }
}

.scrollTop.scrollHeight 是 JavaScript 属性,see here

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

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

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

在第 HTML 页中:

<ion-content #content>

在 .TS 页面中:

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



 constructor(){}

  getInformation(){

//Your Code 

..........

//At the end

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

  }