Vue.js中动态过滤数据并按日期分组展示的实现方案
按日期分组展示事件数据的最优实现方案
需求说明
- 按日期分组展示事件,每个日期标题下显示对应事件列表
- 日期需显示为「X月X日 周X」格式(如2月15日 周三)
- 新增事件时自动归入对应日期分组,无需手动调整
事件数据结构
从API获取的events.data是对象数组,每个事件结构如下:
{ _id: "63e1330539560eaef2612f84", event_date: "2023-02-16T14:00:00.000Z", event_link: "/testLink", event_name: "TestName", price: 12 }
原有实现的问题
你之前用嵌套v-for加v-if的方式,会导致每个日期分组下为所有事件生成div,不符合条件的就变成空DOM节点,既浪费性能又冗余。
最优实现方案
核心思路是先把事件数据按日期预分组为结构化数据,再直接渲染分组结果,彻底去掉模板里的v-if,同时保证响应式更新。
1. 数据分组处理(响应式)
在Vue组件中用计算属性处理分组,这样数据变化时会自动重新计算分组:
Vue3 示例
import { ref, computed } from 'vue' // 存储从API获取的事件数据,用ref保证响应式 const events = ref([]) // 按日期分组的计算属性 const groupedEvents = computed(() => { const dateGroups = {} events.value.forEach(event => { const dateObj = new Date(event.event_date) // 生成分组用的唯一日期键(如"2023-02-15") const dateKey = dateObj.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }) // 生成页面显示的日期文本(如"2月15日 周三") const displayText = dateObj.toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric', weekday: 'short' }) // 初始化分组 if (!dateGroups[dateKey]) { dateGroups[dateKey] = { displayText, eventList: [] } } // 将事件加入对应分组 dateGroups[dateKey].eventList.push(event) }) // 将分组对象转为数组,并按日期排序(早的在前) return Object.values(dateGroups).sort((a, b) => { const dateA = new Date(Object.keys(dateGroups).find(k => dateGroups[k] === a)) const dateB = new Date(Object.keys(dateGroups).find(k => dateGroups[k] === b)) return dateA - dateB }) })
Vue2 示例
export default { data() { return { events: [] // 存储API获取的事件数据 } }, computed: { groupedEvents() { const dateGroups = {} this.events.forEach(event => { const dateObj = new Date(event.event_date) const dateKey = dateObj.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }) const displayText = dateObj.toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric', weekday: 'short' }) if (!dateGroups[dateKey]) { dateGroups[dateKey] = { displayText, eventList: [] } } dateGroups[dateKey].eventList.push(event) }) return Object.values(dateGroups).sort((a, b) => { const dateA = new Date(Object.keys(dateGroups).find(k => dateGroups[k] === a)) const dateB = new Date(Object.keys(dateGroups).find(k => dateGroups[k] === b)) return dateA - dateB }) } } }
2. 模板渲染
直接遍历分组后的数据,模板简洁无冗余:
<div v-for="group in groupedEvents" :key="group.displayText"> <!-- 日期标题 --> <div class="date-title">{{ group.displayText }}</div> <!-- 分隔线 --> <hr class="date-separator" /> <!-- 事件列表 --> <div v-for="event in group.eventList" :key="event._id" class="event-item"> <a :href="event.event_link" class="event-name">{{ event.event_name }}</a> <span class="event-price">价格:{{ event.price }}元</span> <!-- 其他事件字段按需渲染 --> </div> </div>
3. 新增事件的自动分组
因为events是响应式数据,当你从API获取新事件并添加到events数组时,groupedEvents计算属性会自动重新执行分组逻辑,新事件会被自动归入对应日期分组,页面无需手动刷新。
方案优势
- 无冗余DOM:只渲染对应日期的事件,不会生成空div
- 性能更优:分组逻辑仅在数据变化时执行,避免模板层的重复遍历
- 逻辑清晰:数据处理和视图渲染分离,代码更易维护
- 自动响应:新增事件时自动完成分组,无需额外处理
内容的提问来源于stack exchange,提问作者Nehrz
相关产品推荐
相关产品推荐

