[後編]LaravelとVue.jsを使ってリアルタイムChatアプリを作ってみた。

Laravel

前回の記事の続きになります。
[前編]LaravelとVue.jsを使ってリアルタイムChatアプリを作ってみた。

始めに

前編の記事を読んでいない方は、まず前編の記事をお読み下さい。
前編ではLaravelとVue.jsでリアルタイムにメッセージを送受信できる機能について解説しています。
後編のこの記事では、補足機能の実装についての解説になります。

Typing中の実装

ユーザーがメッセージをタイピングしているときに”typing…”を相手側に表示する

resources/js/app.js

 data:{
  message:'',
  chat:{
   message:[],
   user:[],
   color:[]
  },
  typing:''
 },
 watch:{
  message(){
   window.Echo.private('chat')
    .whisper('typing', {
      name: this.message
    });
  }
 },

 mounted(){
  window.Echo.private('chat')
   .listen('ChatEvent', (e) => {
     this.chat.message.push(e.message);
     this.chat.user.push(e.user);
     this.chat.color.push('warning');
     console.log(e);
   })
   .listenForWhisper('typing', (e) => {
     if(e.name!=''){
      //console.log('typing');
      this.typing='typing...';
     }else{
      //console.log('');
      this.typing='';
     }
      //console.log(e.name);
   });
 }

dataにtypingを追加
watchを追加、その中にwindow.Echo.private(‘chat’).whisperを追加
mounted()の中にlistenForWhisperを追加

resources/views/chat.blade.php
以下のタグを追加

<div class="badge badge-info">@{{typing}}</div>

 

右のブラウザで入力中、左側のブラウザではtypingが表示されるようになる。
入力後はtypingが消え、メッセージが表示される。

joinedとleaved時のメッセージ表示

ユーザーがchatに参加したときと、chatから退出したときに通知を画面に出す方法を実装していきます。

v-toasterのインストール

npm i –save v-toaster


resources/js/app.js
以下を追加

import Toaster from 'v-toaster'
import 'v-toaster/dist/v-toaster.css'
Vue.use(Toaster, {timeout: 5000})

またwindow.Echo.join(‘chat’)
this.$toaster.success を使ってユーザーがchatに来た時にメッセージを表示します。(successでメッセージを緑に表示)
this.$toaster.warningでユーザーがchatにを去ったときにメッセージを表示します。(warningでメッセージを黄色に表示)

 window.Echo.join('chat')
  .here((users) => {
    this.numberOfUser = users.length;
    console.log(users);
  })
  .joining((user) => {
    this.numberOfUser += 1;
    this.$toaster.success(user.name + ' joined chat');
    console.log(user.name);
  })
  .leaving((user) => {
    this.numberOfUser -= 1;
    this.$toaster.warning(user.name + ' leaved chat');
  })
  .error((error) => {
  });


resources/views/chat.blade.php

<div class="offset-4 col-md-4 offset-sm-4 col-sm-10">
  <li class="list-group-item active">Chat<span class="badge badge-pill badge-danger">@{{numberOfUser}}</span></li>
  <div class="badge badge-info">@{{typing}}</div>
  <ul class="list-group" v-chat-scroll>
   <message v-for="value,index in chat.message"
    :key=value.index :color=chat.color[index]
    :user=chat.user[index] :time=chat.time[index]>
    @{{value}}
   </message>
  </ul>
  <input type="text" class="form-control" placeholder="Type your message here.." v-model='message' @keyup.enter='send'>
</div>

@{{numberOfUser}} で何人ユーザーがchatに存在するかを表示します。

 

joining-leaving


右側のブラウザをリロードすると、左側のブラウザで “user name + leaved chat” というメッセージが表示され、右側のchatページが再表示されると、左側で“user name + joined chat” というメッセージが表示されるようになります。

※送信時刻の部分についてはapp.jsのmethods内にgetTime()で現在時刻を取得して、mountedされたときに.listen内で以下を追加しています。

this.chat.time.push(this.getTime());

chat.blade.phpにまた以下を追加して、timeを表示するようにします。

:time=chat.time[index]

Chat(メッセージ)をセッションに保存する。

resources/js/app.js
getOldMessages を作ります。

 getOldMessages(){
  axios.post('/getOldMessages')
   .then(response=>{
     console.log(response);
     if(response.data != ''){
      this.chat = response.data;
     }
   })
   .catch(error=>{
     console.log(error);
   })
 }


app/Http/Controllers/ChatController.php
ChatController側にもSaveToSessionとgetOldMessages 関数を定義します。
send関数が呼ばれたときにSaveToSessionを呼ぶようにします。

 public function send(Request $request){
  $user=User::find(Auth::id());
  $this->saveToSession($request);
  event(new ChatEvent($request->message,$user));
 }

 public function saveToSession(Request $request){
  session()->put('chat',$request->chat);
 }

 public function getOldMessages(){
  return session('chat');
 }

 

routes/web.php
getOldMessagesとsaveToSessionのルーティングを追加します。

 Route::post('getOldMessages', [App\Http\Controllers\ChatController::class,'getOldMessages']);
 Route::post('saveToSession', [App\Http\Controllers\ChatController::class,'saveToSession']);


resources/js/app.js

 mounted(){
this.getOldMessages();
window.Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.message.push(e.message);
this.chat.user.push(e.user);
 this.chat.color.push('warning');
this.chat.time.push(this.getTime());
axios.post('/saveToSession',{
chat: this.chat
})
console.log(e);
})

moutedされたときにgetOldMessages関数を呼びだすようにして、またメッセージを受けとる(listen側)ときに、axios.post(‘/saveToSession’, { chat: this.chat } )でメッセージをセッションに保存するようにします。

chatアプリの実装は以上になります。
udemyの講座とも照らし合わせてコードを確認頂くとよいかと思います。
githubにもコードを公開しています。

まとめ

  • 前編と後編の2回に渡り、chatアプリを作成していきました。
  • whisperを利用してメッセージのタイプ中に “typing…”表示する方法を学習していきました。
  • v-toasterを利用して、ユーザーがchatに参加、退出したときにメッセージを表示する方法を学習していきました。
  • メッセージをsessionに保存して、リロードしてもメッセージをchatに表示する方法を学習していきました。
  • Laravel側ではcontrollerとevenを利用した実装について学習していきました。
  • Vue.js側ではwatch, computed, mounted等を用いた実装について学習していきました。
  • pusherの使い方についても触れていきました。

今回作成したリアルタイムchatアプリは拡張性があると思います。
メッセージをDBに保存する機能を追加してみたり、グループチャットを作成する機能を追加してみるのも面白いかと思います。