web-dev-qa-db-ja.com

ionic 2 + angular 2:リスト/ページ/チャットの下部に自動スクロール

「チャット」と「コンテンツ」の2つのセグメントでページをコーディングしようとしています。 1つの「チャット」でページを自動スクロールして、効果なしで下にスクロールするようにします。チャットは<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>

TypeScriptではなくJavascriptを使用していますが、jQueryを使用したくありません。ありがとう:)さらに、「コンテンツ」セグメントに移動して「チャット」に戻ると、チャットを再度自動スクロールしたいと思います。

12
sandrina-p

まず第一に、@ rinukkusuの答えは正しいですが、<ion-content><ion-list>の親)にはいくつかのバグがあるため(私の場合は動作しません)(イオン開発者が作業中です)、その要素にscroll:hiddenを追加し、内部に2番目のコンテンツを作成して自動スクロールを適用します。最後に、適切な(s)cssを使用して、ページが読み込まれ、ユーザーが「チャット」セグメントをクリックするたびに、construtorで関数を呼び出しました。

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

結論:関数は2回呼び出されます。ページが読み込まれたとき(コンストラクター)、ユーザーが「チャット」セグメントに戻るたびに。 (クリック)= "autoScroll()"

これが誰かの助けになることを願っています。より良い方法を知っているなら、私に知らせてください!私は数週間前にAngular2とIonic2で遊んでいたので、ここでは見逃しているかもしれないコンセプト/ベースがたくさんあります。

ありがとう:)

5
sandrina-p

以下がその方法です。

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の重要なビットは、#content on <ion-content>です。 ViewChildを使用してchatPage.js#content識別子を使用して<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
  }
}
28
smukov

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

これは誰かを助けるかもしれません、私は同様の答えを与えました 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プロパティ、 こちらを参照 です。

1

別の解決策は、スクロールビューの変更を「観察」し、自動的にスクロールすることです。つまり、メッセージが表示される新しい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>

(Githubの Ionic2CLI-Meteor-WhatsAppから取得します

1
Gianfranco P.

ユーザーが上にスクロールしようとしたかどうかを確認するチェックを追加しました。

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