
今日は昨日から引き続き、メッセージを表示できるようにしていきます。
今日の内容
・チャットルームでメッセージの表示する
・メッセージを入力したものを表示する
これで今日はやっていきます。
今日の内容
メッセージの表示
昨日の内容でメッセージを保存することはできたのだが、他のファイルにmessages
を渡せていない。
つまり、_id.vue
にはmessages
があるが、messages.vue
のファイルにはmessages
がないということだ。
コンポーネントはお互いが独立しているため、これを連結させる必要がある。
そしてこれをプロパティという機能で連結させようと思う。
コンポーネントについては下記のサイトが詳しく書かれてある。
<template>
<div class="container">
<div class="chats-layout">
<messages :messages="messages" />
</div>
<div class="input-layout">
<chat-form />
</div>
</div>
</template>
以上がプロパティの受け渡し方法である。
:messages
は任意のアトリビュートのため、:hoge
でもなんでもいい。
"messages"
はdata
の値を参照しているため、こちらはマスト。
次に受け取りの方法。Messages
ファイルでは下記のように追加。
<script>
import Message from '~/components/Message'
export default {
props: ['messages'],
components: {
Message,
},
}
</script>
プロパティの略のprops
にmessages
というプロパティを指定する。これは先ほど設定したmessages
。
そしてこのprops
の値を取得できるようにする。
<script>
import Message from '~/components/Message'
export default {
components: {
Message,
},
props: ['messages'],
mounted() {
console.log(this.messages)
},
}
</script>
コンソールを確認してみる。

無事に確認することができた。
これで_id.vue
からMessages.vue
に値を渡すことができた。
ダミーのデータがチャットの画面に表示されていので、v-for
を使ってmessages
のデータを表示できるようにする。
<template>
<div class="chats-container">
<message v-for="message in messages" :key="message" :message="message" />
</div>
</template>
上のデータmessage
をMessage.vue
で受け取る必要があるので、下記のように変更する必要がある。
<script>
export default {
props: ['message'],
computed: {
displayname() {
return '@' + this.message.user.name
},
},
}
</script>
これでMessages.vue
からMessage.vue
にmessage
を渡すことができた。

message
にuser
のデータ(name,thumbnail
)がないからエラーが表示。
HTMLの方のuser
データを一旦コメントアウト。
<template>
<div class="chat-container">
<!--<div class="thumbnail-container">-->
<!-- <img :src="message.user.thumbnail" />-->
<!--</div>-->
<div class="message-container">
<!--<div class="user-name">{{ displayname }}</div>-->
<div class="message">{{ message.text }}</div>
</div>
</div>
</template>
表示できたので、次はメッセージを入力して保存できるようにしようと思う。
メッセージを入力して表示
メッセージを入力できるようにしていく。
ChatForm.vue
を変更していく。
<template>
<div class="input-container">
<textarea @click="login"></textarea>
</div>
</template>
<script>
export default {
methods: {
login() {
window.alert('ログインしてください')
},
},
}
</script>
<style scoped>
.input-container {
padding: 10px;
height: 100%;
}
textarea {
width: 100%;
height: 100%;
}
</style>
現在はこのようになっているので、ここから変更していく。
一旦ログイン機能を削除して、Firestore(データベース)にデータを追加できるようにする。
addメソッドを使って、データを追加するようにする。
それでは、以下のように変更していく。
<template>
<div class="input-container">
<textarea v-model="text"></textarea>
</div>
</template>
<script>
export default {
data(){
return {
text: 'テスト'
}
},
methods: {
login() {
window.alert('ログインしてください')
},
},
}
</script>
v-model
を使い、HTMLで入力された値をJavaScriptで保存できるようにする。
v-model
を使うにはdataを定義する必要があるので、data
でtext
を定義します。
text
のなかにdata
でに定義した'テスト'が表示された。
それでは、メソッドを定義して入力したメッセージを保存できるようにする。
<template>
<div class="input-container">
<textarea v-model="text"></textarea>
</div>
</template>
<script>
import { db } from '~/plugins/firebase'
export default {
data() {
return {
text: null,
}
},
methods: {
addMessage(){
const channelId = this.$route.params.id
db.collection('channels').doc(channelId).collection('messages').add({text: this.text})
},
},
}
</script>
<style scoped>
.input-container {
padding: 10px;
height: 100%;
}
textarea {
width: 100%;
height: 100%;
}
</style>
これでtext
の中にdata
のtext
を追加することができる。
textarea
の中で、Enterキーを押してメッセージを保存する必要があるので、HTMLを下記のように変更。
<template>
<div class="input-container">
<textarea v-model="text" v-on:keydown.enter="addMessage"></textarea>
</div>
</template>
v-on:keydown.enter
でEnterキーが押されたらaddMessageメソッド
を実行できるようになる。
一応アラートも追加する。
<script>
import { db } from '~/plugins/firebase'
export default {
data() {
return {
text: null,
}
},
methods: {
addMessage() {
const channelId = this.$route.params.id
db.collection('channels')
.doc(channelId)
.collection('messages')
.add({ text: this.text })
.then(() => {
alert('メッセージの保存に成功')
})
},
},
}
</script>
firestoreに保存されたが、表示はされない。
それでは表示できるようにしていきたいが、問題発生。
- 日本語の入力中に勝手にメッセージが保存されてしまう
- テキストエリアの中にメッセージが残ってしまう
これを修正していく。
<script>
import { db } from '~/plugins/firebase'
export default {
data() {
return {
text: null,
}
},
methods: {
addMessage(event) {
if (event.keyCode === 229) { return }
const channelId = this.$route.params.id
db.collection('channels')
.doc(channelId)
.collection('messages')
.add({ text: this.text })
.then(() => {
alert('メッセージの保存に成功')
})
},
},
}
</script>
ここで出てくるif (event.keyCode === 229) {return}
では、日本語入力中の場合はreturn
してメッセージを保存しないようにさせている。
229とは上のサイトでも記述されているように、日本語入力中の時のイベントを指す。
上記のコードでもいいのだが、可読性と見た目を考慮して、以下のように変更する。
<template>
<div class="input-container">
<textarea v-model="text" @keydown.enter="addMessage"></textarea>
</div>
</template>
<script>
import { db } from '~/plugins/firebase'
export default {
data() {
return {
text: null,
}
},
methods: {
addMessage(event) {
if (this.enterJapaneseConversion(event)) { return }
const channelId = this.$route.params.id
db.collection('channels')
.doc(channelId)
.collection('messages')
.add({ text: this.text })
.then(() => {
alert('メッセージの保存に成功')
})
},
enterJapaneseConversion(event){
const codeForConversion = 229
return event.keyCode === codeForConversion
}
},
}
</script>
<style scoped>
.input-container {
padding: 10px;
height: 100%;
}
textarea {
width: 100%;
height: 100%;
}
</style>
こんな感じに変更。やっていることは読みやすくしただけ。
enterJapaneseConversion(event) {
const codeForConversion = 229
return event.keyCode === codeForConversion
},
enterJapaneseConversion
というメソッドを作り(名前はテキトー)、event.keycode
の処理を追加しただけです。
これで日本語入力の際に、勝手に保存がされなくなりました。
しかし、テキストエリアにまだ残ったままでなので、 解決します。
addMessage(event) {
if (this.enterJapaneseConversion(event)) {
return
}
const channelId = this.$route.params.id
db.collection('channels')
.doc(channelId)
.collection('messages')
.add({ text: this.text })
.then(() => {
this.text = null
})
},
入力した後に、テキストの中身をなくせば消せるようになりますね。
これでメッセージの保存と表示は完了です。
まとめ
次回はリアルタイムでチャットをできるようにしていきます。
この状態だといちいちリロードしないといけないという問題があります。
次回はその問題を解決します。
最後まで読んでくださりありがとうございました。