Files
gaoYuJournal/miniprogram/components/calendar/index.ts
2025-12-10 14:20:21 +08:00

211 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// components/calendar/index.ts
interface DayInfo {
date: string; // YYYY-MM-DD
year: number;
month: number;
day: number;
isCurrentMonth: boolean;
hasJournal: boolean;
isToday: boolean;
}
interface MonthInfo {
year: number;
month: number;
days: DayInfo[];
}
interface CalendarData {
currentYear: number;
months: MonthInfo[];
scrollIntoView: string; // 滚动到的元素 id
}
Component({
properties: {
// 日记数据key 为日期 YYYY-MM-DDvalue 为日记 id 数组
journalMap: {
type: Object,
value: {}
}
},
data: <CalendarData>{
currentYear: 0,
months: [],
scrollIntoView: ''
},
lifetimes: {
attached() {
this.initCalendar();
}
},
observers: {
'journalMap.**'(journalMap: Record<string, number[]>) {
// 日记数据更新时重新生成所有月份的日期
if (this.data.months.length > 0) {
this.updateAllMonthsDays(journalMap);
}
}
},
methods: {
/** 初始化日历 */
initCalendar() {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1;
this.setData({
currentYear,
months: this.generateYearMonths(currentYear)
});
// 滚动到当前月份
this.scrollToMonth(currentMonth);
},
/** 生成指定年份的 12 个月 */
generateYearMonths(year: number): MonthInfo[] {
const months: MonthInfo[] = [];
const today = new Date();
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
for (let month = 1; month <= 12; month++) {
months.push({
year,
month,
days: this.generateDaysForMonth(year, month, this.data.journalMap || {}, todayStr)
});
}
return months;
},
/** 更新所有月份的日期数据 */
updateAllMonthsDays(journalMap: Record<string, number[]>) {
const { months } = this.data;
const today = new Date();
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const updatedMonths = months.map(monthInfo => ({
...monthInfo,
days: this.generateDaysForMonth(monthInfo.year, monthInfo.month, journalMap, todayStr)
}));
this.setData({ months: updatedMonths });
},
/** 生成指定月份的日期数据 */
generateDaysForMonth(year: number, month: number, journalMap: Record<string, number[]>, todayStr: string): DayInfo[] {
const days: DayInfo[] = [];
// 当前月第一天
const firstDay = new Date(year, month - 1, 1);
const firstDayWeek = firstDay.getDay();
// 当前月最后一天
const lastDay = new Date(year, month, 0);
const lastDate = lastDay.getDate();
// 上个月需要显示的日期
const prevMonthLastDay = new Date(year, month - 1, 0);
const prevMonthLastDate = prevMonthLastDay.getDate();
for (let i = firstDayWeek - 1; i >= 0; i--) {
const day = prevMonthLastDate - i;
const prevMonth = month === 1 ? 12 : month - 1;
const prevYear = month === 1 ? year - 1 : year;
const dateKey = `${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
days.push({
date: dateKey,
year: prevYear,
month: prevMonth,
day,
isCurrentMonth: false,
hasJournal: !!journalMap[dateKey],
isToday: dateKey === todayStr
});
}
// 当前月的日期
for (let day = 1; day <= lastDate; day++) {
const dateKey = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
days.push({
date: dateKey,
year,
month,
day,
isCurrentMonth: true,
hasJournal: !!journalMap[dateKey],
isToday: dateKey === todayStr
});
}
// 下个月需要显示的日期(补齐到 35 个格子6 行)
const remainingDays = 35 - days.length;
for (let day = 1; day <= remainingDays; day++) {
const nextMonth = month === 12 ? 1 : month + 1;
const nextYear = month === 12 ? year + 1 : year;
const dateKey = `${nextYear}-${String(nextMonth).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
days.push({
date: dateKey,
year: nextYear,
month: nextMonth,
day,
isCurrentMonth: false,
hasJournal: !!journalMap[dateKey],
isToday: dateKey === todayStr
});
}
return days;
},
/** 切换年份 */
changeYear(delta: number) {
const newYear = this.data.currentYear + delta;
this.setData({
currentYear: newYear,
months: this.generateYearMonths(newYear)
});
// 滚动到第一个月
this.scrollToMonth(1);
},
/** 上一年 */
prevYear() {
this.changeYear(-1);
},
/** 下一年 */
nextYear() {
this.changeYear(1);
},
/** 滚动到指定月份 */
scrollToMonth(month: number) {
// 先清空,然后设置,触发滚动
this.setData({ scrollIntoView: '' });
wx.nextTick(() => {
this.setData({ scrollIntoView: `month-${month}` });
});
},
/** 点击日期 */
onDayTap(e: WechatMiniprogram.BaseEvent) {
const { date, year, month, day } = e.currentTarget.dataset;
// 触发自定义事件,传递选中的日期信息
this.triggerEvent('dateselect', {
date,
year,
month,
day
});
}
}
});