メッセージコンポーネント

    Messages Vueコンポーネントは、Messagesコンポーネントを表します。

    メッセージコンポーネント

    以下のコンポーネントが含まれています。

    • f7-messages - メインのメッセージコンテナ
    • f7-message - 単一のメッセージ要素
    • f7-messages-title - ひとつのメッセージのタイトル要素

    メッセージのプロパティ

    PropTypeDefaultDescription
    <f7-messages> properties
    initbooleantrueInitializes Messages component
    new-messages-firstbooleanfalseEnable if you want to use new messages on top, instead of having them on bottom
    scroll-messagesbooleantrueEnable/disable messages autoscrolling when adding new message
    scroll-messages-on-edgebooleantrueIf enabled then messages autoscrolling will happen only when user is on top/bottom of the messages view
    typingbooleanfalseAllows to display/toggle typing message indicator
    <f7-message> properties
    typestringsentMessage type: sent (default) or received
    textstringMessage text
    avatarstringMessage user's avatar URL
    namestringMessage user's name
    imagestringMessage image URL
    headerstringMessage header
    footerstringMessage footer
    text-headerstringMessage text header
    text-footerstringMessage text footer
    firstbooleanfalseDefines that the message is first in the conversation
    lastbooleanfalseDefines that the message is last in the conversation
    tailbooleanfalseDefines that the message has visual "tail". Usually last message in conversation
    same-namebooleanfalseDefines that this message sender name is the same as on previous message
    same-headerbooleanfalseDefines that this message header text is the same as on previous message
    same-footerbooleanfalseDefines that this message footer text is the same as on previous message
    same-avatarbooleanfalseDefines that this message user's avatar URL is the same as on previous message

    メッセージイベント

    EventDescription
    <f7-message> events
    clickユーザーがメッセージの泡をクリックするとイベントが発生する
    click:nameユーザーがメッセージのユーザー名をクリックするとイベントが発生する
    click:textユーザがメッセージのテキストをクリックするとイベントが発生する
    click:avatarユーザがメッセージユーザのアバターをクリックするとイベントが発生する
    click:headerユーザがメッセージのヘッダをクリックするとイベントが発生する
    click:footerユーザーがメッセージのフッターをクリックするとイベントが発生する
    click:bubbleユーザがメッセージバブルをクリックするとイベントが発生します。

    メッセージスロット

    シングルメッセージのVueコンポーネント(<f7-message>)には、カスタムエレメント用のスロットが追加されています。

    • default - 要素は、最後に <div class="message-bubble"> 要素の子として挿入されます。
    • start - 要素は先頭に挿入され、メインのメッセージ要素 <div class="message"> の直接の子となります。
    • end - メインのメッセージ要素の直系の子として、最後に要素が挿入されます。
    • content-start - 要素は <div class="message-content"> 要素の先頭に挿入され、その直接の子となります。
    • content-end - <div class="message-content"> 要素の最後に挿入され、直接の子要素となります。
    • bubble-start -
      ` 要素の先頭に挿入され、直接の子要素となります。
    • bubble-end - <div class="message-bubble"> 要素の最後に挿入され、直接の子となります。default` スロットと同じです。

    以下のスロットは、1つのメッセージの中で、より完全なレイアウトを渡したい場合に、同じプロップの代わりに使用することができます。

    • header - 要素はメッセージのヘッダーに挿入されます。
    • footer - メッセージのフッターに挿入される要素です。
    • text - メッセージのテキストに挿入される要素です。
    • name - メッセージの名前に挿入される要素です。
    • image - メッセージのイメージに挿入される要素です(<img> 要素になります)。
    • text-header - メッセージのテキストヘッダーに挿入される要素です。
    • text-footer - メッセージのテキストフッターに挿入される要素です。
    <f7-message
      type="sent"
      text="Hello World"
      name="John Doe"
      avatar="path/to/image.jpg"
    >
      <div slot="start">Start</div>
      <div slot="end">End</div>
      <div slot="content-start">Content Start</div>
      <div slot="content-end">Content End</div>
      <div slot="bubble-start">Bubble Start</div>
      <div slot="bubble-end">Bubble End</div>
    </f7-message>
    
    <!-- にレンダリングされます。 -->
    
    <div class="message message-sent">
      <div>Start</div>
      <div class="message-avatar" style="background-image: url(path/to/image.jpg);"></div>
      <div class="message-content">
        <div>Content Start</div>
        <div class="message-name">John Doe</div>
        <div class="message-bubble">
          <div>Bubble Start</div>
          <div class="message-text">Hello World</div>
          <div>Bubble End</div>
        </div>
        <div>Content End</div>
      </div>
      <div>End</div>
    </div>
    

    Examples

    ここでは、Messagebarと一緒に使用することができるメッセージページの完全な例を示します。

    <template>
    <f7-page>
      <f7-navbar title="Messages" />
    
      <f7-messagebar
        ref="messagebar"
        v-model:value="messageText"
        :placeholder="placeholder"
        :attachments-visible="attachmentsVisible"
        :sheet-visible="sheetVisible"
      >
        <template #inner-start>
          <f7-link
            icon-ios="f7:camera_fill"
            icon-aurora="f7:camera_fill"
            icon-md="material:camera_alt"
            @click="sheetVisible = !sheetVisible"
          />
        </template>
        <template #inner-end>
          <f7-link
            icon-ios="f7:arrow_up_circle_fill"
            icon-aurora="f7:arrow_up_circle_fill"
            icon-md="material:send"
            @click="sendMessage"
          />
        </template>
        <f7-messagebar-attachments>
          <f7-messagebar-attachment
            v-for="(image, index) in attachments"
            :key="index"
            :image="image"
            @attachment:delete="deleteAttachment(image)"
          ></f7-messagebar-attachment>
        </f7-messagebar-attachments>
        <f7-messagebar-sheet>
          <f7-messagebar-sheet-image
            v-for="(image, index) in images"
            :key="index"
            :image="image"
            :checked="attachments.indexOf(image) >= 0"
            @change="handleAttachment"
          ></f7-messagebar-sheet-image>
        </f7-messagebar-sheet>
      </f7-messagebar>
    
      <f7-messages>
        <f7-messages-title><b>Sunday, Feb 9,</b> 12:58</f7-messages-title>
        <f7-message
          v-for="(message, index) in messagesData"
          :key="index"
          :type="message.type"
          :image="message.image"
          :name="message.name"
          :avatar="message.avatar"
          :first="isFirstMessage(message, index)"
          :last="isLastMessage(message, index)"
          :tail="isTailMessage(message, index)"
        >
          <template #text>
            <!-- eslint-disable-next-line -->
            <span v-if="message.text" v-html="message.text"></span>
          </template>
        </f7-message>
        <f7-message
          v-if="typingMessage"
          type="received"
          :typing="true"
          :first="true"
          :last="true"
          :tail="true"
          :header="`${typingMessage.name} is typing`"
          :avatar="typingMessage.avatar"
        ></f7-message>
      </f7-messages>
    </f7-page>
    </template>
    <script>
    import { f7, f7ready } from 'framework7-vue';
    import $ from 'dom7';
    
    export default {
      data() {
        return {
          attachments: [],
          sheetVisible: false,
          typingMessage: null,
          messageText: '',
          messagesData: [
            {
              type: 'sent',
              text: 'Hi, Kate',
            },
            {
              type: 'sent',
              text: 'How are you?',
            },
            {
              name: 'Kate',
              type: 'received',
              text: 'Hi, I am good!',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
            },
            {
              name: 'Blue Ninja',
              type: 'received',
              text: 'Hi there, I am also fine, thanks! And how are you?',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
            },
            {
              type: 'sent',
              text: 'Hey, Blue Ninja! Glad to see you ;)',
            },
            {
              type: 'sent',
              text: 'Hey, look, cutest kitten ever!',
            },
            {
              type: 'sent',
              image: 'https://cdn.framework7.io/placeholder/cats-200x260-4.jpg',
            },
            {
              name: 'Kate',
              type: 'received',
              text: 'Nice!',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
            },
            {
              name: 'Kate',
              type: 'received',
              text: 'Like it very much!',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
            },
            {
              name: 'Blue Ninja',
              type: 'received',
              text: 'Awesome!',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
            },
          ],
          images: [
            'https://cdn.framework7.io/placeholder/cats-300x300-1.jpg',
            'https://cdn.framework7.io/placeholder/cats-200x300-2.jpg',
            'https://cdn.framework7.io/placeholder/cats-400x300-3.jpg',
            'https://cdn.framework7.io/placeholder/cats-300x150-4.jpg',
            'https://cdn.framework7.io/placeholder/cats-150x300-5.jpg',
            'https://cdn.framework7.io/placeholder/cats-300x300-6.jpg',
            'https://cdn.framework7.io/placeholder/cats-300x300-7.jpg',
            'https://cdn.framework7.io/placeholder/cats-200x300-8.jpg',
            'https://cdn.framework7.io/placeholder/cats-400x300-9.jpg',
            'https://cdn.framework7.io/placeholder/cats-300x150-10.jpg',
          ],
          people: [
            {
              name: 'Kate Johnson',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
            },
            {
              name: 'Blue Ninja',
              avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
            },
          ],
          answers: [
            'Yes!',
            'No',
            'Hm...',
            'I am not sure',
            'And what about you?',
            'May be ;)',
            'Lorem ipsum dolor sit amet, consectetur',
            'What?',
            'Are you sure?',
            'Of course',
            'Need to think about it',
            'Amazing!!!',
          ],
          responseInProgress: false,
        };
      },
      computed: {
        attachmentsVisible() {
          const self = this;
          return self.attachments.length > 0;
        },
        placeholder() {
          const self = this;
          return self.attachments.length > 0 ? 'Add comment or Send' : 'Message';
        },
      },
      mounted() {
        const self = this;
        f7ready(() => {
          self.messagebar = f7.messagebar.get(self.$refs.messagebar.$el);
        });
      },
      methods: {
        isFirstMessage(message, index) {
          const self = this;
          const previousMessage = self.messagesData[index - 1];
          if (message.isTitle) return false;
          if (
            !previousMessage ||
            previousMessage.type !== message.type ||
            previousMessage.name !== message.name
          )
            return true;
          return false;
        },
        isLastMessage(message, index) {
          const self = this;
          const nextMessage = self.messagesData[index + 1];
          if (message.isTitle) return false;
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name)
            return true;
          return false;
        },
        isTailMessage(message, index) {
          const self = this;
          const nextMessage = self.messagesData[index + 1];
          if (message.isTitle) return false;
          if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name)
            return true;
          return false;
        },
        deleteAttachment(image) {
          const self = this;
          const index = self.attachments.indexOf(image);
          self.attachments.splice(index, 1)[0]; // eslint-disable-line
        },
        handleAttachment(e) {
          const self = this;
          const index = $(e.target).parents('label.checkbox').index();
          const image = self.images[index];
          if (e.target.checked) {
            // Add to attachments
            self.attachments.unshift(image);
          } else {
            // Remove from attachments
            self.attachments.splice(self.attachments.indexOf(image), 1);
          }
        },
        sendMessage() {
          const self = this;
          const text = self.messageText.replace(/\n/g, '<br>').trim();
          const messagesToSend = [];
          self.attachments.forEach((attachment) => {
            messagesToSend.push({
              image: attachment,
            });
          });
          if (text.length) {
            messagesToSend.push({
              text,
            });
          }
          if (messagesToSend.length === 0) {
            return;
          }
    
          // Reset attachments
          self.attachments = [];
          // Hide sheet
          self.sheetVisible = false;
          // Clear area
          self.messageText = '';
          // Focus area
          if (text.length) self.messagebar.focus();
          // Send message
          self.messagesData.push(...messagesToSend);
    
          // Mock response
          if (self.responseInProgress) return;
          self.responseInProgress = true;
          setTimeout(() => {
            const answer = self.answers[Math.floor(Math.random() * self.answers.length)];
            const person = self.people[Math.floor(Math.random() * self.people.length)];
            self.typingMessage = {
              name: person.name,
              avatar: person.avatar,
            };
            setTimeout(() => {
              self.messagesData.push({
                text: answer,
                type: 'received',
                name: person.name,
                avatar: person.avatar,
              });
              self.typingMessage = null;
              self.responseInProgress = false;
            }, 4000);
          }, 1000);
        },
      },
    };
    </script>