首页/日程页:当前时间红线改为定时器驱动,不再冻结在冷启动时刻 (#81)
用户:首页今天的日程,那个红线,不会动态更新,只有刚打开应用的时候更新, 如果不清后台,就一直不动了。查一下这个更新机制,需要能够动态更新。 根因:nowMin: this.nowMinutes() 是**在 build 里直接调方法** —— ArkUI 不会因为时间流逝重算任何东西,那个方法只在首次 build 时求值一次, 红线永远停在打开 App 那一刻。与 pitfalls 里 ForEach(this.xxx(), ...) 追踪不到 是同一条规则:build 里只有字段(@Local/@Param)建依赖,方法调用不建。 改法:@Local nowClockMin + setInterval 30 秒一跳改它;传参改成读该字段。 - 30 秒而非 1 分钟:1 分钟在整分附近显得迟一拍,30 秒只改一个 number,成本极低; - 先立即刷一次,否则首屏红线停在默认 0(=00:00,跑到视窗外面); - aboutToAppear 起、aboutToDisappear 停 —— 首页切模块走 if/else 分发, 组件会销毁重建,成对钩子必然触发; - 绝不在 build() 里起定时器(build 可能多次调用,定时器会越叠越多)。 顺带修 FbCalendarPage 完全相同的两处(月视图 + 议程视图)—— 用户从首页切过去看到同样的死线。 验证(真机 5NC0225B27004718,红线 #FF3B30 像素扫描): 09:57:22 红线 y=1359.0,10:00:24 y=1366.5(下移 7.5px, 理论 3.03 分钟 = 6.9px,吻合); 切到别的模块再切回后仍在走:1368.5 → 90 秒后 1372.5(4px≈1.75 分钟,吻合), 说明 aboutToDisappear 清掉旧定时器、aboutToAppear 起了新的,无泄漏无停摆。 hvigorw assembleHap BUILD SUCCESSFUL。
This commit is contained in:
@@ -205,6 +205,16 @@ export struct FbCalendarPage {
|
|||||||
@Local showMonth: number = new Date().getMonth() + 1;
|
@Local showMonth: number = new Date().getMonth() + 1;
|
||||||
/** 选中的日期 `YYYY-MM-DD` */
|
/** 选中的日期 `YYYY-MM-DD` */
|
||||||
@Local pickedIso: string = '';
|
@Local pickedIso: string = '';
|
||||||
|
/**
|
||||||
|
* 当前时刻(当天第几分钟)—— 驱动时间轴的**当前时间红线**。
|
||||||
|
*
|
||||||
|
* 🔴 2026-11-06:原来是 `nowMin: this.nowMinutes()`(build 里调方法),
|
||||||
|
* 不建立响应依赖 ⇒ 红线停在进页面那一刻。改成 @Local + 定时器。
|
||||||
|
* 与首页 `FbHomePage.nowClockMin` 完全同一套做法。
|
||||||
|
*/
|
||||||
|
@Local nowClockMin: number = 0;
|
||||||
|
/** 定时器句柄(0 = 没在跑) */
|
||||||
|
private nowTimer: number = 0;
|
||||||
|
|
||||||
// ---- 浮层状态 ----
|
// ---- 浮层状态 ----
|
||||||
/** 详情:正在看的条目(列表里那份) */
|
/** 详情:正在看的条目(列表里那份) */
|
||||||
@@ -339,6 +349,8 @@ export struct FbCalendarPage {
|
|||||||
*/
|
*/
|
||||||
aboutToDisappear(): void {
|
aboutToDisappear(): void {
|
||||||
FB_BACK.unregister('calendar');
|
FB_BACK.unregister('calendar');
|
||||||
|
/* 🔴 2026-11-06:停掉当前时间刷新(见 `startNowTicker()`)。 */
|
||||||
|
this.stopNowTicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
private backOnce(): boolean {
|
private backOnce(): boolean {
|
||||||
@@ -376,6 +388,11 @@ export struct FbCalendarPage {
|
|||||||
this.applyCardJump();
|
this.applyCardJump();
|
||||||
this.load();
|
this.load();
|
||||||
this.loadBooks();
|
this.loadBooks();
|
||||||
|
/* 🔴 2026-11-06:当前时间红线要自己走。
|
||||||
|
用户报的是首页,但这里**完全同一个毛病** —— `nowMin: this.nowMinutes()`
|
||||||
|
在 build 里调方法,不建立响应依赖 ⇒ 红线停在进页面那一刻。
|
||||||
|
既然修了就一起修,否则从首页切到日程页还是同一条死线。 */
|
||||||
|
this.startNowTicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1521,7 +1538,8 @@ export struct FbCalendarPage {
|
|||||||
events: this.eventsOf(this.pickedIso),
|
events: this.eventsOf(this.pickedIso),
|
||||||
style: this.style,
|
style: this.style,
|
||||||
isToday: this.pickedIso === this.todayIso(),
|
isToday: this.pickedIso === this.todayIso(),
|
||||||
nowMin: this.nowMinutes(),
|
/* 🔴 2026-11-06:读 @Local(定时器驱动),不要调方法(不建立依赖) */
|
||||||
|
nowMin: this.nowClockMin,
|
||||||
onPick: (e: FbCalEvent): void => {
|
onPick: (e: FbCalEvent): void => {
|
||||||
this.openEvent(e);
|
this.openEvent(e);
|
||||||
}
|
}
|
||||||
@@ -1534,6 +1552,28 @@ export struct FbCalendarPage {
|
|||||||
return d.getHours() * 60 + d.getMinutes();
|
return d.getHours() * 60 + d.getMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动「当前时间」刷新(与首页 `FbHomePage.startNowTicker` 同一套)。
|
||||||
|
*
|
||||||
|
* · 30 秒一跳:红线是"现在"的指示,1 分钟一跳在整分附近会显得迟一拍;
|
||||||
|
* · 先立即刷一次,避免首屏红线停在默认值 0(= 00:00,跑到视窗外面);
|
||||||
|
* · 只在页面存在期间跑,`aboutToDisappear` 里清掉。
|
||||||
|
*/
|
||||||
|
private startNowTicker(): void {
|
||||||
|
this.stopNowTicker();
|
||||||
|
this.nowClockMin = this.nowMinutes();
|
||||||
|
this.nowTimer = setInterval((): void => {
|
||||||
|
this.nowClockMin = this.nowMinutes();
|
||||||
|
}, 30 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopNowTicker(): void {
|
||||||
|
if (this.nowTimer !== 0) {
|
||||||
|
clearInterval(this.nowTimer);
|
||||||
|
this.nowTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 周视图:7 列日期条 + 选中日日程 */
|
/** 周视图:7 列日期条 + 选中日日程 */
|
||||||
@Builder
|
@Builder
|
||||||
weekBody() {
|
weekBody() {
|
||||||
@@ -1661,7 +1701,7 @@ export struct FbCalendarPage {
|
|||||||
events: g.events,
|
events: g.events,
|
||||||
style: this.style,
|
style: this.style,
|
||||||
isToday: g.iso === this.todayIso(),
|
isToday: g.iso === this.todayIso(),
|
||||||
nowMin: this.nowMinutes(),
|
nowMin: this.nowClockMin,
|
||||||
onPick: (e: FbCalEvent): void => {
|
onPick: (e: FbCalEvent): void => {
|
||||||
this.openEvent(e);
|
this.openEvent(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,6 +337,27 @@ export struct FbHomePage {
|
|||||||
@Local mvCinemas: FbCinemaItem[] = [];
|
@Local mvCinemas: FbCinemaItem[] = [];
|
||||||
@Local mvLoading: boolean = false;
|
@Local mvLoading: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前时刻(当天第几分钟)—— 驱动「今天的日程」时间轴的**当前时间红线**。
|
||||||
|
*
|
||||||
|
* 🔴 用户 2026-11-06:「首页今天的日程,那个红线,不会动态更新,只有刚打开
|
||||||
|
* 应用的时候更新,如果不清后台,就一直不动了。」
|
||||||
|
*
|
||||||
|
* 根因:原来是 `nowMin: this.nowMinutes()` —— **在 build 里直接调用方法**。
|
||||||
|
* ArkUI 不会因为"时间流逝"重算任何东西,那个方法只在首次 build(以及
|
||||||
|
* 别的状态变化引发重绘)时求值一次 ⇒ 红线永远停在打开 App 的那一刻。
|
||||||
|
*
|
||||||
|
* ⇒ 改成 `@Local` 字段 + 定时器主动改它:字段一变,`FbDayEventPanel` 的
|
||||||
|
* `@Param nowMin` 就更新,红线跟着走。这是项目里唯一能让时间自动刷新的
|
||||||
|
* 办法(`@Builder` 里调方法不建立依赖,与 `pitfalls.md` 记的那条同源)。
|
||||||
|
*
|
||||||
|
* ⚠️ 不叫 `nowMin` 而是 `nowClockMin`:`nowMin` 已经被 `nowMinutes()`
|
||||||
|
* 方法占着语义,两个同名字段/方法挨着放容易误改。
|
||||||
|
*/
|
||||||
|
@Local nowClockMin: number = 0;
|
||||||
|
/** 红线的定时器句柄(0 = 没在跑) */
|
||||||
|
private nowTimer: number = 0;
|
||||||
|
|
||||||
/** 「新增成员」表单开着 */
|
/** 「新增成员」表单开着 */
|
||||||
@Local pfCreating: boolean = false;
|
@Local pfCreating: boolean = false;
|
||||||
/** 联系人卡要显示的人(本地库前 N 个) */
|
/** 联系人卡要显示的人(本地库前 N 个) */
|
||||||
@@ -384,10 +405,16 @@ export struct FbHomePage {
|
|||||||
⚠️ 必须**不 await**:本地库首次打开或库很大时读一次要几百毫秒,
|
⚠️ 必须**不 await**:本地库首次打开或库很大时读一次要几百毫秒,
|
||||||
串在上面会让首页首屏白等(而这两张卡是锦上添花)。 */
|
串在上面会让首页首屏白等(而这两张卡是锦上添花)。 */
|
||||||
this.loadSideCards();
|
this.loadSideCards();
|
||||||
|
/* 🔴 2026-11-06:当前时间红线要自己走 —— 见 `startNowTicker()` 的说明。
|
||||||
|
⚠️ 放在这里而不是 build 里:`build()` 可能被调用很多次,
|
||||||
|
在里面起定时器会**越叠越多**(每次都新开一个,旧的没人清)。 */
|
||||||
|
this.startNowTicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutToDisappear(): void {
|
aboutToDisappear(): void {
|
||||||
FB_BACK.unregister('home');
|
FB_BACK.unregister('home');
|
||||||
|
/* 页面销毁 ⇒ 停掉时间刷新,别让已销毁的页面继续收定时器回调(白耗电)。 */
|
||||||
|
this.stopNowTicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 返回手势:先关详情卡,再交给 `Index`(返回 true = 已消费) */
|
/** 返回手势:先关详情卡,再交给 `Index`(返回 true = 已消费) */
|
||||||
@@ -1389,6 +1416,40 @@ export struct FbHomePage {
|
|||||||
return d.getHours() * 60 + d.getMinutes();
|
return d.getHours() * 60 + d.getMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动「当前时间」刷新。
|
||||||
|
*
|
||||||
|
* 🔴 用户 2026-11-06:「红线不会动态更新,只有刚打开应用的时候更新,
|
||||||
|
* 如果不清后台,就一直不动了。」
|
||||||
|
*
|
||||||
|
* 设计取舍:
|
||||||
|
* · **30 秒一跳**,不是 1 分钟:红线是"现在"的视觉指示,1 分钟一跳的话
|
||||||
|
* 用户在整分时刻附近盯着看会觉得"迟了一拍";30 秒的成本极低
|
||||||
|
* (只改一个 number 字段,且值没变时设成同值不会触发重绘)。
|
||||||
|
* · **先立即刷一次**:`aboutToAppear` 里直接调一次,避免首屏红线
|
||||||
|
* 停留在默认值 0(= 00:00,跑到视窗顶部外面去了)。
|
||||||
|
* · **只在页面存在期间跑**(`aboutToDisappear` 里清掉):
|
||||||
|
* 首页切走(`Index` 换模块)会走 `aboutToDisappear`,
|
||||||
|
* 留着定时器就是纯粹的耗电,而且会让已销毁的页面继续收状态更新。
|
||||||
|
* · **不判断"值没变就跳过"**:`@Local` 赋同值本来就不触发重绘,
|
||||||
|
* 多一句判断反而容易写错(比如把比较写成 `>=`)。
|
||||||
|
*/
|
||||||
|
private startNowTicker(): void {
|
||||||
|
this.stopNowTicker();
|
||||||
|
this.nowClockMin = this.nowMinutes();
|
||||||
|
this.nowTimer = setInterval((): void => {
|
||||||
|
this.nowClockMin = this.nowMinutes();
|
||||||
|
}, 30 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 停掉刷新(可重复调用) */
|
||||||
|
private stopNowTicker(): void {
|
||||||
|
if (this.nowTimer !== 0) {
|
||||||
|
clearInterval(this.nowTimer);
|
||||||
|
this.nowTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 今天 → `YYYY-MM-DD`(`FbEventEditSheet` 的 `presetDate` 要这个格式)。
|
* 今天 → `YYYY-MM-DD`(`FbEventEditSheet` 的 `presetDate` 要这个格式)。
|
||||||
*
|
*
|
||||||
@@ -1615,7 +1676,10 @@ export struct FbHomePage {
|
|||||||
events: this.todayEvents,
|
events: this.todayEvents,
|
||||||
style: this.calStyle,
|
style: this.calStyle,
|
||||||
isToday: true,
|
isToday: true,
|
||||||
nowMin: this.nowMinutes(),
|
/* 🔴 2026-11-06:读 `@Local nowClockMin`(定时器驱动),
|
||||||
|
不要写 `this.nowMinutes()` —— 在 build 里调方法不建立依赖,
|
||||||
|
红线会停在打开 App 那一刻(用户报的就是这个)。 */
|
||||||
|
nowMin: this.nowClockMin,
|
||||||
showHead: false,
|
showHead: false,
|
||||||
emptyTitle: '今天没有安排',
|
emptyTitle: '今天没有安排',
|
||||||
emptyHint: '过得轻松一点',
|
emptyHint: '过得轻松一点',
|
||||||
|
|||||||
Reference in New Issue
Block a user