computed 实现日历核心逻辑:自动推导当月天数、首日星期几及上下月占位日期,生成7×6日期网格;起始日由getday()决定补位数,当月天数用new date(year,month+1,0).getdate()获取,总格子固定42个。

用 computed 实现日历组件的日期逻辑,核心是把“当前月有多少天”“第一天星期几”“上月/下月需要补的占位日期”这些动态值,交给 Vue 的响应式系统自动推导——不用手动写一堆 methods 或 watch,数据一变,视图立刻更新。
计算当月日期网格(7×6 表格)
日历本质是一个 7 列 × 最多 6 行的二维数组。关键不是渲染今天,而是算出整个可视区域该显示哪些日期:
-
起始日:当月 1 号是星期几(
new Date(year, month, 1).getDay()),决定前面要补几个上月日期 -
当月天数:用
new Date(year, month + 1, 0).getDate()获取(比如 2024-02 的下月是 3 月,3 月 0 日就是 2 月最后一天) - 总格子数:固定 42 个(6 行 × 7 列),不足就用上月/下月日期补全
代码示例(Vue 3 Composition API):
const calendarDays = computed(() => {const firstDay = new Date(props.year, props.month, 1).getDay(); // 0~6
const daysInMonth = new Date(props.year, props.month + 1, 0).getDate();
const prevMonthDays = new Date(props.year, props.month, 0).getDate();
const days = [];
// 上月补位
for (let i = firstDay - 1; i >= 0; i--) {
days.push({ date: new Date(props.year, props.month - 1, prevMonthDays - i), isCurrentMonth: false });
}
// 当月主体
for (let i = 1; i days.push({ date: new Date(props.year, props.month, i), isCurrentMonth: true });
}
// 下月补位(补满 42 个)
const remaining = 42 - days.length;
for (let i = 1; i days.push({ date: new Date(props.year, props.month + 1, i), isCurrentMonth: false });
}
return days;
});
自动识别今天、选中日、范围高亮
这些状态不需额外监听,直接在 computed 里比对即可:
-
是否为今天:用
date.toDateString() === new Date().toDateString() -
是否被选中:对比
date和响应式变量selectedDate(同样用toDateString()避免时分秒干扰) -
是否在日期范围内(如双日历选择区间):检查
date是否介于rangeStart和rangeEnd之间(注意边界处理)
把这些判断内联进 calendarDays 的每个 item 里,模板中直接绑定 class:
date: new Date(...),
isCurrentMonth: true,
isToday: date.toDateString() === new Date().toDateString(),
isSelected: selectedDate.value?.toDateString() === date.toDateString(),
isInRange: rangeStart.value && rangeEnd.value
? date >= rangeStart.value && date : false
});
联动切换月份时,computed 自动刷新
只要 props.year 和 props.month 是响应式的(比如通过 v-model 或父组件传入的 ref),上面所有 computed 都会自动重新执行。无需手动调用方法或清空缓存。
- 点击「上月」按钮 → 修改
monthRef.value--→ 所有依赖它的computed重算 - 跳转到某年某月 → 同时更新
yearRef和monthRef→ 视图瞬时更新 - 即使用户快速连点,也不会出现状态错乱,因为 Vue 的响应式调度保证了最终一致性
性能提示:避免在 computed 中做重操作
computed 是惰性求值且带缓存的,但要注意别在里面做以下事:
- 不要发起网络请求(用
watch或onMounted替代) - 避免重复创建大量 Date 对象(上面示例已复用,没问题)
- 如果日历支持十年跨度切换,可加一层记忆化(如用 Map 缓存 year+month → days 数组),但普通场景没必要
真正需要响应式更新的,只是“当前显示哪个月”,其余全是纯函数推导 —— 这正是 computed 最擅长的事。










