LoginSignup
0
1

More than 1 year has passed since last update.

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

Posted at

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1