Vue が Web オンラインチャット機能を実現

Vue が Web オンラインチャット機能を実現

この記事では、Webオンラインチャットを実装するためのVueの具体的なコードを参考までに紹介します。具体的な内容は次のとおりです。

最終的な効果

実装プロセス

無限スクロールフォームの実装については、以前にも紹介したので、ここでは繰り返しません。よくわからない場合は、前のドキュメントのポータルから確認できます。

リアルタイムオンラインチャットの主な機能

  • 2 日間のウィンドウの上部までスクロールすると、履歴情報やその他の情報が自動的に読み込まれます。データの読み込み中は、読み込みアニメーションが必要です。
  • メッセージを送信すると、スクロールバーが自動的にウィンドウの下部にスライドし、送信したメッセージがチャット ウィンドウに表示されます。
  • 他の人からメッセージを受信したときに、ウィンドウ内のスクロールバーの位置を決定する必要があります。メッセージが下から一定の範囲内で受信された場合、自動的にウィンドウの下部にスライドする必要があります。
  • 送受信したメッセージをチャットステータスに繰り返し表示することはできません。
  • 送信されたメッセージと受信されたメッセージは、チャット ウィンドウに逆の順序で表示される必要があります。つまり、ウィンドウの下部に近いメッセージが最新のメッセージになります。
  • 認証のためには、WebSocket を介してバックエンドと長い接続を確立するのが最適です。新しいメッセージがある場合、バックエンドは積極的にメッセージをフロントエンドにプッシュします。ここでは、フロントエンドにチャットウィンドウを実装するというアイデアを主に紹介し、WebSocket 部分は拡張しません。タイマーポーリングによって単純に実装されます。

さっそくコードを見てみましょう

バックエンドの戻りデータ形式

すべての設計と機能実装はデータに基づいていると思うので、まずはバックエンドから返されるデータ形式を見てみましょう。

{
 "code": 200, // 応答コード "msg": "OK", // 応答メッセージ "total": 1, 
 "sysTime": "2020-12-16 15:23:27", // システム応答時間 "data": [{
  "avatar": "", // ユーザーアバター "content": "{\"type\":\"txt\",\"msg\":\"こんにちは! \"}", // メッセージの内容"isRead": 0, // 既読ですか? "isOneself": 0, // 自分から送信されたメッセージですか? 0 は未読、1 は既読"msgId": 10, // メッセージ ID、重複排除に使用"nickName": "碧海燕鱼", // ユーザーのニックネーム"userCode": "202012162030202232" // ユーザー コード}]
}

ここで注目すべきは、コンテンツ フィールドは JSON 形式の文字列データを返すことであり、コンテンツの形式は次のようになります。

// テキストメッセージ {
  "タイプ": "txt",
  "msg":"Hello" //メッセージの内容}
// 画像メッセージ {
  "タイプ": "画像",
  "url": "画像アドレス",
  "拡張子":"jpg",
  "幅":360、//幅"高さ":480、//高さ"サイズ": 388245
}
// ビデオメッセージ {
  「タイプ」: 'ビデオ',
  「URL」: "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
  "拡張子":"mp4",
  "幅":360、//幅"高さ":480、//高さ"サイズ": 388245
}
// 場所メッセージ {
  "タイプ": "ローカル",
  "address":"No. 599, Wangshang Road, Hangzhou, Zhejiang, China", //地理的位置 "longitude":120.1908686708565, // 経度 "latitude":30.18704515647036 // 緯度}

HTMLコード

<テンプレート>
  <Modal title="オンラインコミュニケーション" v-model="chatVisible"
   ドラッグ可能
   フッターを非表示
   :width="580" @on-cancel="キャンセル">
   <div class="チャット">
     <div class="チャットメッセージ本文" id="チャットフォーム" @scroll="スクロール"
      >
      <スピンv-if="読み込み中">
        <アイコン type="ios-loading" size=18 class="spin-icon-load"></アイコン>
      </スピン>
        <div dis-hover v-for="(item,index) in data"
         :key="index" class="メッセージカード">
         <div :class="item.isOneself == 1?'メッセージ行右':'メッセージ行左'">
           <img :src="item.avatar?item.avatar:defualtアバター" 
            高さ="35" 幅="35" >
            <div class="メッセージコンテンツ"> 
              <div :style="item.isOneself == 1?'text-align:right;display: flex;flex-direction:row-reverse':''">
                {{item.ニックネーム}}
                <span class="メッセージ時間">
                   {{item.createTime}} </span>
                </div>
              <div class="メッセージ本文">
                {{item.content.msg}}
                </div>
             </div> 
          </div>
         </div>
      </div>
        <入力
        v-model="フォーム.msg"
        タイプ="テキストエリア"
        スタイル="margin:10px 0;"
        placeholder="もっと積極的に行動すれば、世界はもっと広がります!"
        :行数="4"
      />
     </div>
     <div class="footer-btn">
        <Button @click="cancel" type="text">キャンセル</Button>
        <Button type="primary" @click="sendMsg">送信</Button>
      </div>
  </モーダル>
</テンプレート>

注意:自分と他人が送信したメッセージの表示スタイルは異なるため、isOneself フィールドを使用して表示スタイルを区別する必要があります。

JavaScript コード

<スクリプト>
"@/api/index" から {listMsg,sendMsg } をインポートします。
エクスポートデフォルト{
  名前:「チャット」、
  小道具: {
    価値: {
      タイプ: ブール値、
      デフォルト: false
    }
  },
  データ() {
    戻る {
      チャット可視:this.value、
      読み込み中:false、
      defualtAvatar:require('../../assets/defult-avatar.svg'), // バックエンドはデフォルトのアバターを返しません。注: ローカルファイル data:[] に動的にアクセスするには、require リクエストメソッドが必要です。
      distincData:[], // メッセージ重複排除配列 offsetMax:0, // 最大オフセット、現在の最大 ID を記録し、将来スケジュールされた時間にデータをポーリングするたびにこの ID より大きいデータのみを取得します offsetMin:0, // 最小オフセット、現在の最小 ID を記録し、上にスライドするたびにこの ID より大きいデータのみを取得します searchForm:{ // データが取得または初めて読み込まれるたびに送信されるフォームデータ pageNumber: 1,
        ページサイズ: 20
      },
      form:{ // データを送信するフォームコンテンツ:"",
        メッセージ:""
      },
      timerSwitch:0 // タイマースイッチ、デフォルトでは閉じています};
  },
  メソッド: {
    初期化(){
      
    },
    loadMsg(){ // デフォルトではフォームが開き、データのページが読み込まれます。フォームは一定期間に 1 回実行されます。let that = this;
      this.searchForm.offsetMax = this.offsetMax;
      listMsg(this.searchForm).then(res=>{
        (res.code == 200)の場合{
          res.data.forEach(e => {
            // 最大オフセットをマークします if (that.offsetMax < e.msgId) {
                that.offsetMax = e.msgId;
            }
            JSON を解析します。
            that.data.unshift(e)
            that.distincData.push(e.msgId);
            // 最大オフセットをマークします。バックエンドから返されるデータは逆順なので、最後の ID が最新です。that.offsetMin = e.msgId;
           });
          // データの読み込みが完了すると、スクロール バーがフォームの一番下までスクロールします。this.scrollToBottom();
        }
      });
       
        
    },
    show(){ //フォームを開いてデータを初期化します //データを初期化します this.data = [];
      this.distincData = [];
      this.offsetMax = 0;
      this.offsetMin = 0;
      this.searchForm.pageNumber = 1;
      this.searchForm.pageSize = 20;
      this.form = {
        コンテンツ:""、
        メッセージ:""
      };
      このメソッドは、
      this.chatVisible = true;
      // タイマーをオンにします this.timerSwitch = 1;
      これを再ロードします。
    },
    sendMsg(){ // メッセージを送信 if(!this.form.msg){
         this.$Message.warning("空のメッセージを送信できません");
        戻る;
      }
      let content = { // メッセージ本文をカプセル化 type:"txt",
        メッセージ:このフォームのメッセージ
      }; 
      this.form.content = JSON.stringify(content);
      sendOrderMsg(this.form).then(res=>{
        (res.code == 200)の場合{
          データを JSON にパースします。
          this.data.push(res.data)
          このフォームのmsg="";
          this.distincData.push(res.data.msgId);
          スクロールダウン
          // メッセージを送信すると、現在のメッセージのみが返されます。相手側がすでにメッセージを送信している可能性があるため、オフセットは変更されません。}
      });
    },
    scrollToBottom(){ //フォームの一番下までスクロールします this.$nextTick(()=>{
          チャットフォームを document.getElementById("チャットフォーム");
          チャットフォームのスクロールトップ = チャットフォームのスクロール高さ;
      });
    },
    // 一番上までスクロールし、ページング パラメータに従って履歴データを取得します。オフセットマークを変更する必要はありませんが、再スクロールを判断する必要があります(){
      チャットフォームを document.getElementById("チャットフォーム");
      scrollTop を chatform.scrollTop とします。
      スクロールトップ == 0 の場合
        this.loading = true; です。
        that = this とする;
        this.searchForm.offsetMin = this.offsetMin;
        this.searchForm.offsetMax = "";
        listMsgByOrder(this.searchForm).then(res=>{
           this.loading = false; です。
            (res.code == 200)の場合{
              res.data.forEach(e => {
                if (that.distincData.indexOf(e.msgId) < 0) {
                  JSON を解析します。
                  that.data.unshift(e);
                  that.distincData.push(e.msgId);
                  // 最小オフセットを変更する if (that.offsetMin > e.msgId) {
                      that.offsetMin = e.msgId;
                  }
                }
              });
            }
        });
      }
    },
   リロードデータ(){
    // タイマースイッチがオンかどうかを判断します。オンの場合はタイマーを実行します。if(this.timerSwitch){
      タイムアウトを設定する(() => {
        パラメータを {} とします。
        パラメータ.ページ番号 = 1;
        パラメータ.pageSize = 20;
        パラメータのオフセットMax = this.offsetMax;
        that = this とする;
        listMsgByOrder(params).then(res=>{
          (res.code == 200)の場合{
            res.data.forEach(e => {
              // 最大オフセットを変更し、重複チェックの前に配置して、現在のメッセージがメッセージリストに追加されるのを防ぎますが、オフセット値はそこにありません if (that.offsetMax < e.msgId) {
                  that.offsetMax = e.msgId;
              }
              if (that.distincData.indexOf(e.msgId) < 0) {
                JSON を解析します。
                that.data.push(e)
                that.distincData.push(e.msgId);
                // 新しいメッセージを受信し、高さを決定します。現在のスクロール バーの高さが下から 100 未満の場合、一番下までスライドします。let chatform = document.getElementById("chatform");
                ギャップをchatform.scrollHeight -chatform.scrollTopとします。
                if(ギャップ >0 && ギャップ < 400){
                  スクロールダウン
                }
              }
            });
            that.reloadData();
          }
        });
      },1000*2);
    }
    
   },
   cancel(){ // フォームを閉じるには、プロンプトタスクスイッチもオフにする必要があります。 this.chatVisible = false;
     this.timerSwitch = 0;
   }
  },
  マウント() {
  }
};
</スクリプト>

CSSコード

<スタイル lang="less">
   。メッセージ {
        高さ: 350ピクセル;
    }
  .ivu-card-body {
    パディング:5px;
  }
  .ivu-modal-body{
    パディング: 0px 16px 16px 16px;
  }
  .チャットメッセージ本文{
   背景色:#F8F8F6;
   幅:545px;
   高さ: 350ピクセル;
   オーバーフロー:自動;
  }
  .メッセージカード{
   マージン:5px;
  }
  .メッセージ行左 {
   ディスプレイ: フレックス;
   flex-direction:行;
  }
  .メッセージ行右 {
   ディスプレイ: フレックス;
   flex-direction:行の反転;
  }
  .メッセージコンテンツ{
    マージン:-5px 5px 5px 5px;
    ディスプレイ: フレックス;
    flex-direction:列;
  }
  .メッセージ本文{
    境界線:1px 実線 #D9DAD9;
    パディング:5px;
    境界線の半径:3px;
    背景色:#FFF;
  }
  .メッセージ時間{
    マージン:0 5px;
    フォントサイズ:5px;
    色:#D9DAD9;
  }
  .footer-btn {
    フロート:右;
    下部マージン: 5px;
  }
  .スピンアイコンロード{
    アニメーション:ani-spin 1s 線形無限;
  }
  @keyframes アニスピン{
    フォーム{transform:rotate(0deg);}
    50% {変換: 回転(180度);}
    {transform: rotate(360deg);} へ
  }
</スタイル>

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Vue+express+Socketでチャット機能を実現
  • Vueはチャットインターフェースを実装する
  • Vue+ウェブ端末がWeChatウェブ版チャットルーム機能を模倣
  • Vue.js は WeChat チャットウィンドウを模倣してコンポーネント機能を表示します
  • Vue + socket.io はシンプルなチャットルームのサンプルコードを実装します
  • Vue2ベースのモバイルQQを模倣したシングルページアプリケーション機能(チャットボットへのアクセス)
  • RongCloud IM を使用して Vue Cli 3 プロジェクトにチャット機能を実装する方法
  • Vue で実装された WeChat ロボット チャット機能の例 [ソース コードのダウンロードあり]
  • Vue と Websocket をベースにした複数人用オンライン チャット ルーム
  • オンラインチャットを実現するVue+sshフレームワーク

<<:  Centos での TCPWrappers アクセス制御の実装

>>:  MySQL は、元のデータと同じデータがある場合、更新ステートメントを再度実行しますか?

推薦する

CSS3 引用のソースと出典をマークする方法

疫病のせいで家にこもりきりで、頭がおかしくなりそうなので、パソコンを起動して頭を働かせてみました。今...

Element PlusはAffixを実装します

目次1. コンポーネントの紹介2. ソースコード分析2.1 テンプレート2.2 スクリプト2.3 実...

Js クラスの構築と継承のケースの詳細な説明

JS のクラスの定義や継承は本当に多様なので、別のノートブックを開いて記録しておきます。意味オブジェ...

高度な CSS の 3 つの方法を使用して複数行の省略を実装するサンプル コード

序文これは古くからの要望ですが、オンラインで解決策を探している人はまだ多く、特に検索結果の上位にラン...

Navicatは機能ソリューション共有を作成できません

初めて MySQL FUNCTION を書いたとき、エラーが何度も発生しました。 Err] 1064...

ハイパーリンクのWebデザイン原則

<br />関連記事: Web コンテンツ ページ作成のための 9 つの実用的なヒント、...

Linux のメモリ管理とアドレス指定の詳細な紹介

目次1. コンセプトメモリ管理モード住所種別分類例: 2. ページ管理x86 アーキテクチャ 32 ...

Windows サーバー ファイルをローカルにバックアップする方法、Windows サーバー データ バックアップ ソリューション

重要なデータはバックアップする必要があり、リアルタイムでバックアップする必要があります。そうしないと...

JavaScript が Taobao の虫眼鏡効果を模倣

この記事では、淘宝虫眼鏡効果を実現するためのJavaScriptの具体的なコードを参考までに紹介しま...

Linux のファイル権限とグループ変更コマンドの詳細な説明

Linux では、すべてがファイルであり (ディレクトリもファイルです)、各ファイルにはユーザーに対...

mysql explain(分析インデックス)の使い方の詳しい説明

EXPLAIN は、MySQL がインデックスを使用して選択ステートメントを処理し、テーブルを結合す...

40以上の美しいWebフォームデザイン例

Web フォームは、訪問者と Web サイト所有者間の主要なコミュニケーション チャネルです。フィー...

jsでの位置計算を徹底的に理解するのに役立つ記事

目次導入スクロール要素.スクロール()要素.scrollHeight/scrollWidth要素.s...

マークアップ言語 - Web アプリケーション CSS スタイル

123WORDPRESS.COM HTML チュートリアル セクションに戻るには、ここをクリックして...

テーブル関連の配置とJavascript操作テーブル、tr、td

適切に機能するテーブル プロパティ設定:コードをコピーコードは次のとおりです。 <テーブル セ...