LINEのように自身のメッセージとその他のメッセージを区別し、自身のメッセージを右側に表示させる。
chat.vue
<transition-group name="chat" tag="div" class="list content">
<!--chatの中の{ key, name, image, message ,userid }をそれぞれ取得-->
<section v-for="{ key, name, image, message, userid } in chat" :key="key">
<div v-if="userid === user.uid" class="myitem flex">
<!-- 自身 -->
<!--「画像」の指定-->
<!--「名前」と「メッセージ」の指定-->
<div class="mydetail">
<div class="mytime">time</div>
<div class="mymessage">
<nl2br tag="div" :text="message" />
</div>
</div>
<div class="myimage flex">
<img :src="image" width="40" height="40" />
<div class="myname">name</div>
</div>
</div>
<div v-else class="otheritem flex">
<!-- 自身ではない -->
<!--「画像」の指定-->
<div class="otherimage flex">
<img :src="image" width="40" height="40" />
<div class="othername">name</div>
</div>
<!--「名前」と「メッセージ」の指定-->
<div class="otherdetail">
<div class="othermessage">
<nl2br tag="div" :text="message" />
</div>
<div class="othertime">time</div>
</div>
</div>
</section>
</transition-group>
chat.vue
<script>
import firebase from "firebase";
import Nl2br from "vue-nl2br";
// 改行を <br> タグに変換するモジュール
export default {
components: { Nl2br },
data() {
return {
user: {}, // ユーザー情報
chat: [], // 取得したメッセージを入れる配列
input: "", // 入力したメッセージ
usersData: [],
profileDeta: {}
};
},
created() {
firebase.auth().onAuthStateChanged(user => {
this.user = user ? user : {};
//firebase.database()で以下のデータベースの読み書きを行う。
const ref_message = firebase.database().ref(this.$route.params.id);
//[router.vue]にて「/ ~ /:id」と指定しルートがマッチした時、
if (user) {
this.chat = [];
ref_message.limitToLast(10).on("child_added", this.childAdded);
} else {
// message に変更があったときのハンドラを解除
ref_message.limitToLast(10).off("child_added", this.childAdded);
}
});
~ 省略 ~
},
childAdded(snap) {
const message = snap.val();
this.chat.push({
key: snap.key,
name: message.name,
image: message.image,
message: message.message,
userid: message.userid
});
console.log(this.chat);
this.scrollBottom();
},
doSend() {
if (this.user.uid && this.input.length) {
// firebaseに書き込まれたメッセージを追加
firebase
.database()
.ref(this.$route.params.id)
.push(
{
message: this.input,
name: this.user.displayName,
image: this.user.photoURL,
userid: this.user.uid,
},
() => {
this.input = ""; // フォームを空にする
}
);
}
}
}
};
</script>
.list {
width: 75%;
margin-bottom: 100px;
}
.content {
margin: 0 auto;
padding: 0 10px;
// -- mymessage -- //
.myitem {
position: relative;
margin: 2rem;
}
.mytime {
color: $white-color;
margin-right: 0.5rem;
display: flex;
align-items: flex-end;
}
.mymessage {
display: inline-block;
position: relative;
margin: 0 20px 0 0;
padding: 10px;
max-width: 460px;
border-radius: 12px;
background: #00ec0ccb;
z-index: 5;
}
.mymessage::before {
position: absolute;
content: " ";
display: block;
right: -16px;
bottom: 12px;
border: 4px solid transparent;
border-left: 12px solid #00ec0ccb;
}
.myname {
color: $white-color;
font-size: 75%;
margin-top: 0.5rem;
font-weight: bold;
}
.myimage {
flex-direction: column;
padding-left: 1.4rem;
img {
border-radius: 20px;
vertical-align: top;
display: flex;
align-items: flex-end;
}
}
.mydetail {
margin: 0 0 0 auto;
display: flex;
}
// -- othermessage -- //
.otheritem {
position: relative;
margin: 2rem;
justify-content: flex-start;
}
.othertime {
color: $white-color;
margin-left: 0.5rem;
display: flex;
align-items: flex-end;
}
.othermessage {
display: inline-block;
position: relative;
margin: 0 0 0 20px;
padding: 10px;
max-width: 460px;
border-radius: 12px;
background: #00ec0ccb;
z-index: 5;
}
.othermessage::before {
position: absolute;
content: " ";
display: block;
left: -16px;
bottom: 12px;
border: 4px solid transparent;
border-right: 12px solid #00ec0ccb;
}
.othername {
color: $white-color;
font-size: 75%;
margin-top: 0.5rem;
font-weight: bold;
}
.otherimage {
flex-direction: column;
padding-right: 1.4rem;
img {
border-radius: 20px;
vertical-align: top;
}
}
.otherdetail {
margin: 0 0 0 1.4em;
display: flex;
.othername {
font-size: 75%;
}
}
}
chat.vue
<section v-for="{ key, name, image, message, userid } in chat" :key="key">
<div v-if="userid === user.uid" class="myitem flex">
<!-- 自身 -->
<!--「画像」の指定-->
<!--「名前」と「メッセージ」の指定-->
<div class="mydetail">
<div class="mytime">time</div>
<div class="mymessage">
<nl2br tag="div" :text="message" />
</div>
</div>
<div class="myimage flex">
<img :src="image" width="40" height="40" />
<div class="myname">name</div>
</div>
</div>
<div v-else class="otheritem flex">
<!-- 自身ではない -->
<!--「画像」の指定-->
<div class="otherimage flex">
<img :src="image" width="40" height="40" />
<div class="othername">name</div>
</div>
<!--「名前」と「メッセージ」の指定-->
<div class="otherdetail">
<div class="othermessage">
<nl2br tag="div" :text="message" />
</div>
<div class="othertime">time</div>
</div>
</div>
</section>
「v-if関数」と「v-else関数」を使用して、「自身」と「その他」の区別をしています。
「自身」「その他」をそれぞれ作成します。
chat.vue
childAdded(snap) {
const message = snap.val();
this.chat.push({
key: snap.key,
name: message.name,
image: message.image,
message: message.message,
userid: message.userid
});
console.log(this.chat);
this.scrollBottom();
},
doSend() {
if (this.user.uid && this.input.length) {
// firebaseに書き込まれたメッセージを追加
firebase
.database()
.ref(this.$route.params.id)
.push(
{
message: this.input,
name: this.user.displayName,
image: this.user.photoURL,
userid: this.user.uid,
},
() => {
this.input = ""; // フォームを空にする
}
);
上記でthis.user.uidをuseridと追加しておき、表示処理の部分でuseridとuser.uidを比較し(v-ifを使用)、
同じなら自身の書き込みとするようにします。
これでロジックとしては完成になります。
あとは自身のメッセージのみ右寄せさせるようにCSSを書いていきます。
chat.vue
.myitem {
position: relative;
margin: 2rem;
}
.mytime {
color: $white-color;
margin-right: 0.5rem;
display: flex;
align-items: flex-end;
}
.mymessage {
display: inline-block;
position: relative;
margin: 0 20px 0 0;
padding: 10px;
max-width: 460px;
border-radius: 12px;
background: #00ec0ccb;
z-index: 5;
}
.mymessage::before {
position: absolute;
content: " ";
display: block;
right: -16px;
bottom: 12px;
border: 4px solid transparent;
border-left: 12px solid #00ec0ccb;
}
.myname {
color: $white-color;
font-size: 75%;
margin-top: 0.5rem;
font-weight: bold;
}
.myimage {
flex-direction: column;
padding-left: 1.4rem;
img {
border-radius: 20px;
vertical-align: top;
display: flex;
align-items: flex-end;
}
}
.mydetail {
margin: 0 0 0 auto;
display: flex;
}
これでLINEのように自身のメッセージの場合は右寄せに、その他のメッセージでは左寄せになるよう実装することが出来ました。