You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue/JavaScript中如何实现聊天消息按日期有序分组排列

问题背景

当前使用Vue开展开发工作,遇到通用JavaScript问题:调用接口获取聊天UI所需的聊天消息,接口初始返回由聊天消息对象组成的数组,数据结构如下:

data: [
  0: {id: 1, created_at: "2022-05-20T15:12:40.000000Z", updated_at: "2022-05-20T17:18:03.000000Z",…}
  1: {id: 2, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
  2: {id: 3, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
  3: {id: 4, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
]

需求是对消息做格式化处理,在聊天窗口中按日期对消息分组。最初编写的分组逻辑为Vue中的computed计算属性,代码如下:

const formattedChats = computed(() => {
  let dateFormattedMessages = messages.value.map(message => {
    return {...message, updated_at: new Date(message.updated_at).toDateString(), created_at: new Date(message.created_at).toDateString()}
  })
  return dateFormattedMessages.reduce((total, currentValue) => {
    total[currentValue.updated_at] = total[currentValue.updated_at] || [];
    total[currentValue.updated_at].push(currentValue);
    return total;
  }, Object.create(null));
})

原代码逻辑为:先遍历每个聊天对象,将其updated_at和created_at字段转换为日期字符串,再基于updated_at字段对数组做分组,运行后得到的结果如下:

formattedChats = {
  Fri Jun 24 2022: [
    {...}, {...
  ]
  Fri May 20 2022:[
    {...}, {...
  ]
  Mon Jun 27 2022:Array[
    {...}, {...
  ]
  Sat May 21 2022:Array[
    {...}, {...
  ]
  Tue Jun 28 2022:Array[
    {...}, {...
  ]
}
存在的问题
  • 分组后生成的对象日期键没有按时间先后顺序排列,直接渲染到UI会导致聊天消息日期顺序混乱,不符合聊天界面的预期展示效果。
  • 本质原因是普通JavaScript对象的键排序规则不可靠,且原始逻辑没有做时间排序处理,遍历消息时的键插入顺序和日期先后顺序不一致。
解决方案

不要依赖普通对象的键顺序做UI渲染,改为输出有序数组结构供模板遍历,同时前置排序逻辑保证时间顺序正确,修正后的计算属性代码如下:

const formattedChats = computed(() => {
  // 格式化日期字段,同时保留时间戳用于排序,避免重复转日期
  const processedMessages = messages.value.map(message => {
    const updateTime = new Date(message.updated_at)
    const createTime = new Date(message.created_at)
    return {
      ...message,
      _updateTimestamp: updateTime.getTime(),
      updated_at: updateTime.toDateString(),
      created_at: createTime.toDateString()
    }
  })

  // 先对单条消息按更新时间从早到晚排序,需要最新消息在前就交换a、b顺序
  processedMessages.sort((a, b) => a._updateTimestamp - b._updateTimestamp)

  // 按日期分组
  const groupMap = Object.create(null)
  processedMessages.forEach(msg => {
    groupMap[msg.updated_at] = groupMap[msg.updated_at] || []
    groupMap[msg.updated_at].push(msg)
  })

  // 转为有序数组,兜底做日期排序,直接供模板渲染
  return Object.entries(groupMap)
    .map(([dateLabel, msgList]) => ({
      date: dateLabel,
      messages: msgList
    }))
    .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
})

模板层直接遍历返回的有序数组即可,无需额外处理排序:

<template>
  <div class="chat-wrapper">
    <div v-for="dateGroup in formattedChats" :key="dateGroup.date" class="date-block">
      <div class="date-tag">{{ dateGroup.date }}</div>
      <div v-for="msg in dateGroup.messages" :key="msg.id" class="message-item">
        <!-- 消息内容渲染逻辑 -->
      </div>
    </div>
  </div>
</template>

注意:不同JS引擎对普通对象的键排序规则存在差异,整数键、字符串键、Symbol键的排序逻辑不统一,涉及有序渲染的场景优先使用数组结构,可控性和兼容性更好。

内容的提问来源于stack exchange,提问作者NwaiwuIsidore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 14:24:22