https://a.storyblok.com/f/270183/76533/8f4c774ae2/e_infinite-scrolling_1200x600.png

無限にスクロールするチャットページネーション

最終更新日 February 3, 2020

所要時間:18 分

注:この記事で説明されているツールや方法の中には、サポートが終了しているものや最新のものではないものもあります。最新の内容やサポートについては 最新記事または ドキュメンテーション

前回の記事に引き続き BootstrapでシンプルなメッセージングUIを作成するこの記事では、Conversation APIからページ分割されて配信されるようになったVonage Conversation Client SDKを使って、会話から古いメッセージをロードする方法を紹介します。

前提条件

ノードとNPM

始めるには、NodeとNPMをインストールする必要があります。このガイドではNode 8とNPM 6を使用します。これらがインストールされ、最新であることを確認してください。

node --version npm --version

NodeとNPMの両方が正しいバージョンでインストールされている必要があります。nodejs.orgにアクセスして、正しいバージョンをインストールしてください。

Vonage CLI

アプリケーションをセットアップするには、Vonage CLIをインストールする必要があります。ターミナルでNPMを使ってインストールする。

npm install @vonage/cli -g

APIキーとシークレットは ダッシュボードで確認することができます。

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

Vonage CLIにはプラグインがあり、インストールすると追加機能を提供します。このチュートリアルではConversationsを扱うので、そのプラグインをインストールするコマンドを以下に示します:

vonage plugins:install @vonage/cli-plugin-conversations

Git(オプション)

gitを使って デモ・アプリケーションをGitHubからクローンできます。

gitコマンドが苦手な方もご心配なく。このガイドには、プロジェクトをZIPファイルとしてダウンロードする手順が含まれています。

この を参照してください。.

はじめに

前回のチュートリアルで完成したアプリをもとに、新しいデモアプリを用意しました。以下の手順でクローンを作成し、インストールしてください。

デモアプリを入手する

git clone https://github.com/nexmo-community/infinite-scrolling-pagination.git

gitコマンドに不慣れな方は、以下をご利用ください。 デモ・アプリケーションをzipファイルとしてダウンロードしをダウンロードしてローカルで解凍してください。

クローンまたは解凍したら、新しいデモ・アプリケーション・ディレクトリに移動します。

cd infinite-scrolling-pagination

npmの依存関係をインストールします。

npm install

環境ファイルを使ってアプリケーション・ポートを設定する。サンプル・ファイルをコピーしてください:

cp .env.example .env

次に、環境ファイル .envを編集し、ポートを3000に設定する。

# app config PORT=3000

前回のコマンドでインストールされた他のパッケージの中に nodemonというパッケージがある。

標準的な方法でアプリケーションを起動するには、以下を実行する:

npm start

nodemonの代わりにアプリケーションを起動するには、以下を実行する:

npm run dev

ヒントこのチュートリアルの続きで nodemonでアプリケーションを実行している場合、私がアプリケーションの再起動を勧めるたびに、その必要はありません。 nodemonがやってくれるからです。しかし、アプリケーションの再認証が必要な場合、セッション情報はメモリに保存され、他のストレージを使用するように設定されていないため、再認証を行う必要があります。

デモアプリの設定

Vonageに接続し、サービスからメッセージを送受信するには、デモ・アプリケーションを設定する必要があります。

Vonageアプリケーションの作成

まず、RTC(リアルタイム通信)機能を持つVonageアプリケーションを作成します。イベントURLは、Vonageサービス上で発生したイベントのライブログとなります。例えば、ユーザーの参加/退出、メッセージの送信、オーディオの有効化(有効化したい場合)などです。

vonage apps:create "Vonage RTC Chat" --rtc_event_url=http://example.com

Vonageの会話を作成する

次に、Vonage Conversationを作成します。Vonage Conversationはチャットルームのような役割を果たします。または、メッセージやイベントのコンテナ。

vonage apps:conversations:create "Infinite Scrolling"

ユーザーの作成

次に、自分用のユーザーを作成する。

注意このデモでは、2人のユーザー間でのチャットは行いません。他のガイドでは、複数のユーザー間で会話を作成する方法を紹介しています。このガイドでは、シンプルかつ魅力的な方法でメッセージ UI をスタイリングすることに重点を置いています。

vonage apps:users:create USER_NAME --display_name=DISPLAY_NAME

ユーザーを会話に追加する

次に、新しいユーザーを会話に追加します。ユーザーはアプリケーションのメンバーでも構いませんが、会話に参加する必要があります。

vonage apps:conversations:members:add CONVERSATION_ID USER_ID

ユーザートークンの生成

最後に、新しいユーザーにトークンを生成します。このトークンは、アプリケーションにアクセスするときのユーザーを表します。このアクセストークンはユーザーを識別するため、このトークンを使用する人は正しいユーザーであるとみなされます。

実際には、このトークンを使ってアプリケーションを設定します。本番環境では、トークンは厳重に管理され、秘密にされ、クライアント・アプリケーションに公開されるとしても非常に注意深くされるべきです。

vonage jwt --key_file=./vonage_rtc_chat.key --acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}' --subject=USER_NAME --app_id=APP_ID

アプリケーションの設定

必要なパーツをすべて生成したら views/layout.hbsファイルを編集し、ここに示すJavaScriptを見つける。

<script>
      var userName = '';
      var displayName = '';
      var conversationId = '';
      var clientToken = '';
    </script>

上記のコマンドで生成した値でコンフィグを編集する。

<script>
      var userName = 'luke'; // <USER_NAME>
      var displayName = 'Luke Oliff'; // <DISPLAY_NAME>
      var conversationId = 'CON-123...y6346'; // <CONVERSATION_ID>
      var clientToken = 'eyJhbG9.eyJzdWIiO.Sfl5c'; // this will be much much longer
    </script>

これで設定されたので、アプリケーションを起動し、デフォルトのアプリケーションURLである デフォルトのアプリケーションURL.

注意:これはあくまでもデモであり、アプリケーション、特にクライアントにクレデンシャルを公開するようなアプリケーションに、クレデンシャルをハードコーディングすべきではない。

Vonage Chat Simple Messaging UIVonage Chat Simple Messaging UI

メッセージ履歴の作成

スクロールするメッセージが増えるので、複数のメッセージをクライアントに送信して、メッセージの履歴を作成してください。デフォルトのページサイズは 20 アイテムなので、20 以上のメッセージを作成します。履歴を2ページ分読み込めるように、60通のテストメッセージを作成することをお勧めします。

アプリにページネーションを追加する

アプリケーションのデフォルト設定では、会話の過去のイベントから20のアイテムが返されるだけです。さて、ユーザーが古いイベントをロードできるように、アプリケーションにページネーションを追加しましょう。

ページネーションとは?

ページネーション(ページング)とは、アプリケーションがコンテンツを複数のページに分割する方法である。APIの設計で実装された場合、それは通常プログラム的にナビゲートすることができ、結果の管理可能なコレクションの配信を可能にします。Vonage Conversation Client SDKのようなSDKも同様で、APIのページネーション機能を拡張し、ページネーションをより簡単にするフレンドリーなメソッドを提供しています。

ユーザー・エクスペリエンス

アプリケーションによっては、「次へ」や「前へ」のようなリンクや、ページ番号を提供するものもあります。しかし、ここで実装するのはそれとは違います。チャットチャンネルのメッセージは連続した会話の流れなので、このアプリはユーザーが過去のメッセージをスクロールし続けることを可能にします。これは、無限スクロールとして知られている概念を使用して行われます。古いメッセージをスクロールして最後まで行くと、アプリは次の履歴ページを要求し、それらを挿入する。履歴がたくさんある古いチャンネルでは、これは永遠にスクロールできる感覚、または無限スクロールを与えるだろう。

コード

さて、これからコードを書いていきます。ここでは、メッセージリストのスクロール位置を検出し、最も古いメッセージに到達したときに、より多くのメッセージを読み込むように変更します。一番古いメッセージはウィンドウの一番上に表示されます。

トップにスクロール

一番上にスクロールしたことを検出するには、新しいイベントを追加する必要があります。ファイルを編集して public/javascripts/chat.jsファイルを編集して setupUserEvents()メソッドの下に以下のコードを追加します。

// public/javascripts/chat.js

// ...

  setupUserEvents() {

    // ...

    this.messageFeed.addEventListener("scroll", () => {
        alert('scrolling!');
    }
  }

// ...

これをブラウザでテストしてみると、あまり役に立たない理由がすぐにわかるだろう。このコードでは messageFeed要素にイベントリスナーを追加しているため、スクロールしようとするたびにポップアップが表示されます。つまり、スクロールしようとするたびにポップアップが表示されるのです!

そこで、少し変更する。以下のコードを setupUserEvents()メソッドの上に以下のコードを追加し、新しいイベントリスナーを図のように変更します。

// public/javascripts/chat.js

// ...

  isFeedAtTop() {
    return 0 === this.messageFeed.scrollTop;
  }

  setupUserEvents() {

    // ...

    this.messageFeed.addEventListener("scroll", () => {
      if (this.isFeedAtTop()) {
        alert('scrolling!');
      }
    }
  }

// ...

この新しい変更により、スクロール位置が messageFeedのスクロール位置が 0であるか、ゼロであるか、あるいはメッセージ履歴の一番上の開始位置であるかを検出する新しいメソッドを作成します。より便利になりました!これで、誰かがメッセージリストの一番上の一番古いメッセージに到達したときがわかります。

Vonage Chat Alert When Scrolling to the TopVonage Chat Alert When Scrolling to the Top

あなたは誰?

会話履歴から新しいメッセージが読み込まれたときに、そのメッセージをそのユーザーに帰属させるには、そのメッセージを保存する必要があります。ファイルを編集し public/javascripts/chat.jsファイルを編集し this.conversation = conversation;.

// public/javascripts/chat.js

// ...

  setupConversationEvents(conversation, user) {
    // ...
    this.user = user;
    // ...
  }

// ...

ページコンテキストの保存

メッセージ履歴からさらにメッセージをロードするには、最後にロードされたページを知る必要があります。そのためには public/javascripts/chat.jsファイルを編集したまま、既存の showConversationHistoryを変更し、アプリケーションの最新のイベント・ページを保存します。

// public/javascripts/chat.js

// ...

  showConversationHistory(conversation, user) {
    // ...
      .then((eventsPage) => {
        this.lastPage = eventsPage;
        var eventsHistory = "";
    // ...
  }

// ...

変更後の showConversationHistoryメソッドがどのように見えるかわからない場合は、ここに変更を適用したメソッド全体を示します。

// public/javascripts/chat.js

// ...

  showConversationHistory(conversation, user) {
    conversation
      .getEvents({ page_size: 20, order: 'desc' })
      .then((eventsPage) => {
        this.lastPage = eventsPage;
        var eventsHistory = "";

        eventsPage.items.forEach((value, key) => {
          if (conversation.members.get(value.from)) {
            switch (value.type) {
              case 'text':
                eventsHistory = this.senderMessage(user, conversation.members.get(value.from), value) + eventsHistory;
                break;
              case 'member:joined':
                eventsHistory = this.memberJoined(conversation.members.get(value.from), value) + eventsHistory;
                break;
            }
          }
        });

        this.messageFeed.innerHTML = eventsHistory + this.messageFeed.innerHTML;

        this.scrollFeedToBottom();
      })
      .catch(this.errorLogger);
  }

// ...

このメソッドのアイデアは EventsPageを呼び出して返された値を保存することである。 getEvents後でアプリが再び使えるようにすることです。

この変更により、アプリケーションは最新のページを認識するようになった。

不必要な要求を避ける

オブジェクトの EventsPageオブジェクトの1つのメソッドは hasNextで、ロードするイベントがまだある場合は真を返す。

メソッドで hasNextメソッドで、先ほど追加したスクロールイベントを編集して this.lastPage.hasNext()を条件に追加します。 alert.

// public/javascripts/chat.js

// ...

  setupUserEvents() {

    // ...

    this.messageFeed.addEventListener("scroll", () => {
      if (this.isFeedAtTop() && this.lastPage.hasNext()) {
        alert('scrolling!');
      }
    }
  }

// ...

これで、読み込むべき別のイベントページがある場合にのみアラートが表示されるようになる。

次のページを読み込む

次のページをロードするには、イベント・リスナーの alertを以下のコードに置き換えてください:

// public/javascripts/chat.js

// ...

        this.lastPage
          .getNext()
          .then((eventsPage) => {
            this.lastPage = eventsPage;
            var moreEvents = "";

            eventsPage.items.forEach((value, key) => {
              if (this.conversation.members.get(value.from)) {
                switch (value.type) {
                  case 'text':
                    moreEvents = this.senderMessage(this.user, this.conversation.members.get(value.from), value) + moreEvents;
                    break;
                  case 'member:joined':
                    moreEvents = this.memberJoined(this.conversation.members.get(value.from), value) + moreEvents;
                    break;
                }
              }
            });

            this.messageFeed.innerHTML = moreEvents + this.messageFeed.innerHTML;
          })
          .catch(this.errorLogger);

// ...

このコードでは this.lastPageこのコードでは、この記事の最初のほうでアプリケーションに格納されていた getNextを返します。 EventsPage.

ここで見られる残りのコードは this.LastPageメソッドとほぼ同じ機能を実行する。 showConversationHistoryメソッドとほぼ同じ機能を実行する。 messageFeed.

スクロール位置を固定する

無限スクロールを使用すると、新しいメッセージが一番上に追加されることに気づくでしょう。 messageFeedの一番上を見ていることになり、チャネルのメッセージ履歴のどこにいたのかわからなくなってしまいます。これを修正するには scrollToメソッドを再利用します。 public/javascripts/chat.jsファイルにあるメソッドを再利用します。

以前は scrollToの高さより大きな数値を指定することで、メッセージの一番下までスクロールさせることができました。 messageFeed.このチームでは、. messageFeed.

もし、アプリケーションが新しいメッセージを読み込んだときの位置が 0が更新される前と後の高さの差にスクロールするのが理にかなっています。 messageFeedが更新される前と後の高さの差をスクロールすることになります。

スクロール位置と hasNextコードを実行する前に the.lastPage.getNext()を保存するコードを追加します。 scrollHeightを格納するコードを追加する:

// public/javascripts/chat.js

// ...
      if (this.isFeedAtTop() && this.lastPage.hasNext()) {
        this.scrollHeight = this.messageFeed.scrollHeight;

        // ...
// ...

さて、この同じ関数で messageFeed.innerHTMLを更新する行の後に moreEventsを更新する行の後に、次の行も追加する:

// public/javascripts/chat.js

// ...
            // ...

            this.scrollTo(this.messageFeed.scrollHeight-this.scrollHeight);
// ...

変更後の "scroll"変更後のイベント・リスナーがどのように見えるかわからない場合は、ここにコード全体を示します:

// public/javascripts/chat.js

// ...

    // ...

    this.messageFeed.addEventListener("scroll", () => {
      if (this.isFeedAtTop() && this.lastPage.hasNext()) {
        this.scrollHeight = this.messageFeed.scrollHeight;

        this.lastPage
          .getNext()
          .then((eventsPage) => {
            this.lastPage = eventsPage;
            var moreEvents = "";

            eventsPage.items.forEach((value, key) => {
              if (this.conversation.members.get(value.from)) {
                switch (value.type) {
                  case 'text':
                    moreEvents = this.senderMessage(this.user, this.conversation.members.get(value.from), value) + moreEvents;
                    break;
                  case 'member:joined':
                    moreEvents = this.memberJoined(this.conversation.members.get(value.from), value) + moreEvents;
                    break;
                }
              }
            });

            this.messageFeed.innerHTML = moreEvents + this.messageFeed.innerHTML;

            this.scrollTo(this.messageFeed.scrollHeight-this.scrollHeight);
          })
          .catch(this.errorLogger);
      }
    });

// ...

運が良ければ、スクロール位置の上にメッセージが読み込まれ、「無限大」、つまり一番上までスクロールできることに気づくだろう。

Vonage Chat Infinite Scrolling to the TopVonage Chat Infinite Scrolling to the Top

終わり

この記事は、前回の記事 BootstrapでシンプルなメッセージングUIを作るメッセージ履歴をスクロールしながら古いメッセージを読み込む方法を紹介します。

ご質問、フィードバック、アドバイス、より広いコミュニティと共有したいアイデアなどがありましたら、お気軽に私たちの コミュニティ・スラックワークスペースに飛び込んでくるか、下記👇に返信してください。

シェア:

https://a.storyblok.com/f/270183/250x250/451101b4f0/lukeoliff.png
Luke Oliffヴォネージの卒業生

フレンドリーな技術教育者、家族思い、多様性チャンピオン、たぶんちょっと議論しすぎ。元バックエンドエンジニア。JavaScript(フロントエンドまたはバックエンド)、素晴らしいVue.js、DevOps、DevSecOps、JamStackのことなら何でも。DEV.toのライター