【Vue × Realtime Detabase】LINEのように自身のメッセージとその他のメッセージを区別し、自身のメッセージを右側に表示させる。

#LINEのように自身のメッセージとその他のメッセージを区別し、自身のメッセージを右側に表示させる。

```html: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>
```

```javascript: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>
```

```css 
  .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%;
      }
    }
  }

```

```html: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関数」を使用して、「自身」と「その他」の区別をしています。

「自身」「その他」をそれぞれ作成します。

```javascript: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を書いていきます。


```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のように自身のメッセージの場合は右寄せに、その他のメッセージでは左寄せになるよう実装することが出来ました。