用户反馈:月视图滑动切换月份后会"跳一下",整月没有任何一天被选中。 期望:切到下个月后,**同样的日号**保持选中(如 11/2 → 12/2)。 ## 根因 handleSwiperChange 只改了 displayYear/displayMonth,**完全没动 selectedDate**。 于是 selectedDate 还停在上个月,而新月份所有格子的 dateMs 都变了, `cell.dateMs === this.selectedDate` 永远为 false ⇒ 整月无选中。 ## 修法 翻月后把 selectedDate 迁到新月份的同一天;该月没有这天时钳到月底 (1/31 → 2/28,与 incForFreq 的钳制策略一致)。 ## 顺带修掉日号漂移 单纯的"钳制"有个副作用:1/31 → 2/28 → 3/28 → 4/28 … 日号被永久改成 28,翻到有 31 天的月份也回不去了。 加 `preferredDay` 记录**用户主动选中的日号**(点日期时更新,翻月时不更新): 偏好31号:1/31 → 2/28(钳制显示) → 3/31(回到偏好) → 4/30 → 5/31 "月末"的语义得以保留。 ## 验证 脚本 18 项全通过(跨年、闰年 2/29、大月小月、连续翻月、往前往后)。 真机实测: 11月2日 → 左滑 → 12月,选中圆存在(144×144) → 再左滑 → 2027年1月,圆内日期仍是"2" ## 教训 "只改显示状态、不改选中状态"是日历类视图的高频 bug。 翻页/翻月时,凡是与"当前选中项"绑定的视觉(高亮、背景), 都要检查选中项本身有没有跟着迁移 —— 否则 diff 时匹配不上就全空白。
65 lines
2.3 KiB
JavaScript
65 lines
2.3 KiB
JavaScript
// 验证 preferredDay 机制消除日号漂移
|
|
function addMonths(y, m, delta) {
|
|
let mm = m + delta, yy = y;
|
|
while (mm < 0) { mm += 12; yy--; }
|
|
while (mm > 11) { mm -= 12; yy++; }
|
|
return [yy, mm];
|
|
}
|
|
function migrate(preferredDay, y, m, delta) {
|
|
const nm = addMonths(y, m, delta);
|
|
const lastDay = new Date(nm[0], nm[1] + 1, 0).getDate();
|
|
return { ms: new Date(nm[0], nm[1], Math.min(preferredDay, lastDay)).getTime(), y: nm[0], m: nm[1] };
|
|
}
|
|
function fmt(ms) {
|
|
const d = new Date(ms);
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
}
|
|
|
|
let pass = 0, fail = 0;
|
|
function ok(name, cond, extra) {
|
|
if (cond) { console.log(' ✅', name); pass++; }
|
|
else { console.log(' ❌', name, extra); fail++; }
|
|
}
|
|
|
|
// 1. 偏好 31 号:1/31 → 2/28 → 3/31(回到 31!)
|
|
let pref = 31, y = 2026, m = 0, cur = new Date(2026, 0, 31).getTime(), log = [];
|
|
for (let i = 0; i < 4; i++) {
|
|
const r = migrate(pref, y, m, 1);
|
|
cur = r.ms; y = r.y; m = r.m;
|
|
log.push(fmt(cur));
|
|
}
|
|
console.log(' 偏好31号连续翻月:', log.join(' → '));
|
|
ok('1/31→2/28→3/31→4/30(月底语义保留)',
|
|
log[0] === '2026-02-28' && log[1] === '2026-03-31' && log[2] === '2026-04-30',
|
|
log.join(','));
|
|
ok('第4次翻到5月回到31', log[3] === '2026-05-31', log[3]);
|
|
|
|
// 2. 偏好 15 号:一直稳定
|
|
pref = 15; y = 2026; m = 0; log = [];
|
|
for (let i = 0; i < 6; i++) {
|
|
const r = migrate(pref, y, m, 1);
|
|
y = r.y; m = r.m; log.push(fmt(r.ms));
|
|
}
|
|
ok('偏好15号稳定', log.every(s => s.endsWith('-15')), log.join(','));
|
|
|
|
// 3. 用户点 2/28 后偏好变 28,翻到 3 月应是 28 号
|
|
pref = 28; y = 2026; m = 1;
|
|
let r = migrate(pref, y, m, 1);
|
|
ok('点过28号后翻月为3/28', fmt(r.ms) === '2026-03-28', fmt(r.ms));
|
|
|
|
// 4. 闰年偏好 31
|
|
pref = 31; y = 2028; m = 0;
|
|
r = migrate(pref, y, m, 1);
|
|
ok('闰年 1/31 → 2/29', fmt(r.ms) === '2028-02-29', fmt(r.ms));
|
|
r = migrate(pref, 2028, 1, 1);
|
|
ok('闰年 2/29 → 3/31', fmt(r.ms) === '2028-03-31', fmt(r.ms));
|
|
|
|
// 5. 往前翻同样保留
|
|
pref = 31; y = 2026; m = 2; // 3月
|
|
r = migrate(pref, y, m, -1);
|
|
ok('3/31 上月 → 2/28', fmt(r.ms) === '2026-02-28', fmt(r.ms));
|
|
r = migrate(pref, 2026, 1, -1);
|
|
ok('2/28 再上月 → 1/31', fmt(r.ms) === '2026-01-31', fmt(r.ms));
|
|
|
|
console.log(`\n结果:通过 ${pass},失败 ${fail}`);
|
|
process.exit(fail === 0 ? 0 : 1); |