Vue Js условное закрытие тега div

#javascript #api #vue.js

#javascript #API #vue.js

Вопрос:

У меня есть API, возвращающий сообщения чата в следующем объекте.

 messages : [

    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       sent_at: "2020-09-26",
       date_group: "Today",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-25",
       date_group: "Yesterday",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-25",
       date_group: "Yesterday",
    ],
    [
       sender: "John Doe",
       text: "Some message",
       sent_at: "2020-09-24",
       date_group: "Thursday",
    ],
]
  

Вместо фильтрации и группировки messages по date_group , а затем повторной сортировки по дате и отображению, я просто сравниваю текущее сообщение date_group с предыдущим сообщением и, если date_group оно отличается, печатаю его.

     printDateGroup(messageKey) {
        return this.messages[messageKey - 1] amp;amp; this.messages[messageKey].date_group !== this.messages[messageKey - 1].date_group
            || messageKey === 0;
    },
  

Пока все работает нормально, но все сообщения теперь печатаются в одном div. Что вызывает проблемы с липкой позицией date_group .

В настоящее время я печатаю их следующим образом.

 <div class="d-flex flex-column message-wrapper">
    <template v-for="(message, idx) in messages">
        <div v-if="printDateGroup(idx)" class="date-label">
            <span>{{ message.date_group }}</span>
        </div>
        <div class="message-text">{{message.text}}</div>
    </template>
</div>
  

Вместо этого я хотел бы отобразить их по div одному date_group , как показано ниже.

 <div class="d-flex flex-column message-wrapper">
     <div class="date-wrapper">
         <div class="date-label">Yesterday</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
     </div>
     <div class="date-wrapper">
         <div class="date-label">Today</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
         <div class="message-text">Some message</div>
     </div>
</div>
  

Я пытался открыть div, а не закрывать его, как мы делаем, php но это не работает.

Ответ №1:

Вы не можете сделать это в vue, но вы можете реорганизовать свою модель данных.

Это пример компонента, который работает так, как вам нужно:

 <template>
  <div class="d-flex flex-column message-wrapper">
    <template v-for="(group) in groups">
      <div class="date-wrapper">

        <div class="date-label">
          {{ group.name }}
        </div>
        <div v-for="message in group.messages" class="message-text">{{message.text}}</div>
      </div>
    </template>
  </div>
</template>

<script>
  export default {
    name: "index",
    computed: {
      messages() {
        return [
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-26",
            date_group: "Today",
          },
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-26",
            date_group: "Today",
          },
          {
            sender: "John Doe",
            sent_at: "2020-09-26",
            date_group: "Today",
          },
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-25",
            date_group: "Yesterday",
          },
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-25",
            date_group: "Yesterday",
          },
          {
            sender: "John Doe",
            text: "Some message",
            sent_at: "2020-09-24",
            date_group: "Thursday",
          },
        ]
      },
      groups() {
        const res = [];
        for (let i = 0; i < this.messages.length; i  ) {
          if (this.printDateGroup(i)) {
            res.push({
              name: this.messages[i].date_group,
              messages: [this.messages[i]]
            })
          } else {
            res[res.length - 1].messages.push(this.messages[i])
          }
        }
        return res;
      }
    },
    methods: {
      printDateGroup(messageKey) {
        return this.messages[messageKey - 1] amp;amp; this.messages[messageKey].date_group !== this.messages[messageKey - 1].date_group
          || messageKey === 0;
      },
    }
  }
</script>
  

Причиной такого состояния является дизайн Vue.

Ответственность за моделирование данных лежит на стороне js, потребности в шаблонах содержат только простейшие операции, такие как for или if , но более продвинутая обработка должна выполняться в части компонентов js.

Комментарии:

1. ну да, я это сделал, но, как я уже сказал, если в чате 100 сообщений, он будет фильтроваться много времени, чего я пытаюсь избежать, но обязательно буду использовать этот подход в качестве последнего средства.

2. Вы можете наблюдать проблемы с эффективностью для 5k — 50k сообщений. Ниже этого уровня вы не должны видеть никаких проблем со временем рендеринга.