fix(首页): 来信卡默认收起,等 /letters 结果再决定显示 —— 修掉「先冒出来再缩回去」的闪烁 (v26092003)
现象:从商城切回首页加载 mama-box 时,先渲染出一张「宝宝来信/宝宝回信啦」卡 (用内置样例信 + 本地待投递队列拼的),几百毫秒后 /letters 回来说没有未读, 卡又缩回去,闪一下。 原因:卡在 index.html 里默认可见,pushLatestToHome() 是「先显示、数据回来再决定」; 而首屏渲染远早于 /letters。 改法(反过来:没确定之前一律不显示): - index.html:#homeLetter 默认带 .hide、#homeBody 默认带 .no-letter(首屏按「无卡」排版,不跳) - app.js:新增 lettersResolved 开关;pushLatestToHome() 在未确定、访客态(无 openid)、 或后端明确未建档(pregEmpty)时一律保持收起;applyRemoteLetters 的每条终态 (成功/空列表/接口挂/无身份)与 applyRemoteProfile 的访客分支都置位并重算 - 访客分支顺手补了一次 pushLatestToHome():此前清空 LETTERS 后没人重算, 那张卡会顶着一封已不存在的信留在首页 验证(本地 + 延迟代理四态,浏览器实测): - 有建档 + 0 封信:全程 hidden(修的就是这个) - 有建档 + 1 封未读:接口回来前 hidden → 回来后显示「小汤圆来信」 - 接口全挂:回退内置样例照旧显示(离线行为不变) - 访客(无 openid):hidden
This commit is contained in:
19
index.html
19
index.html
@@ -7,7 +7,7 @@
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title>兜爸心选 · 孕育陪伴</title>
|
||||
<!-- V:26092002 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<!-- V:26092003 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
|
||||
<link rel="stylesheet" href="mama-box.css">
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
|
||||
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
|
||||
@@ -121,8 +121,17 @@
|
||||
|
||||
<!-- 宝宝一有新回信,pushLatestToHome() 会把这张卡换成那条回信,
|
||||
并加上 .has-new(信封右上角冒一个小红点)。
|
||||
没有未读、也没有新回信时,同一个函数会给它挂 .hide 整张收起来。 -->
|
||||
<button class="letter-card ripple" id="homeLetter" data-goto="letter-detail">
|
||||
没有未读、也没有新回信时,同一个函数会给它挂 .hide 整张收起来。
|
||||
|
||||
⚠️ 2026-09-20:这张卡**默认就是收起的**(标记里直接带 .hide,
|
||||
#homeBody 直接带 .no-letter)。原因:卡的最终显隐要等 /letters
|
||||
回来才知道,而首屏渲染远早于它 —— 默认显示的话,就会出现
|
||||
「先冒出一张(用内置样例/本地队列拼出来的)来信卡,数据回来发现
|
||||
没有未读,再缩回去」的闪一下(商城↔首页来回切时特别明显)。
|
||||
所以规则改成:**没确定之前一律不显示,确认有未读/新回信才显示**。
|
||||
pushLatestToHome() 里的 lettersResolved 就是这个「已确定」开关,
|
||||
别把这里的 .hide / .no-letter 去掉 —— 去掉就退回闪烁版。 -->
|
||||
<button class="letter-card ripple hide" id="homeLetter" data-goto="letter-detail">
|
||||
<span class="lc-envwrap"><img class="lc-env" src="assets/img/02cf420f0d07.png" alt="" aria-hidden="true"></span>
|
||||
<div class="lc-body">
|
||||
<!-- ⚠️ 这句只是**没填小名时的兜底**,屏幕上实际由 pushLatestToHome()
|
||||
@@ -137,6 +146,8 @@
|
||||
|
||||
<!-- id 是给 pushLatestToHome() 用的:来信卡收起来时它挂 .no-letter,
|
||||
把下面第一块(.tool-dock)的上间距补回来。
|
||||
⚠️ 2026-09-20:它**默认就带 .no-letter**(与 #homeLetter 默认带 .hide 配套,
|
||||
首屏按「没有来信卡」排版,避免数据回来时布局跳一下)。
|
||||
|
||||
── 这一版首页正文换了骨架 ──
|
||||
上一版是同一套「竖色条标题 + 灰色说明 + 一块内容」原样重复四遍
|
||||
@@ -150,7 +161,7 @@
|
||||
.shelf 横向可滑的书架卡带
|
||||
页面也因此有了两种宽度节奏:文字型内容仍在 26px 栏内,
|
||||
托盘和卡带出血到屏幕边缘。 -->
|
||||
<div class="home-body" id="homeBody">
|
||||
<div class="home-body no-letter" id="homeBody">
|
||||
<!-- 模块一 · 工具托盘。
|
||||
抬头进了托盘里面:标题独占一行,右端「所有工具」做成白底细边胶囊;
|
||||
说明单独做成一枚浅色 chip,不再是标题底下一行贴边的灰字。
|
||||
|
||||
45
js/app.js
45
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26092002';
|
||||
var VER = '26092003';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -1319,10 +1319,30 @@
|
||||
全读完了还硬顶一封旧信在首页正中间,是在假装有新消息。
|
||||
收起来会空出 64px 的流高(卡是 margin-top:-16 + height:80),
|
||||
所以同时给 .home-body 挂 .no-letter 把下面的标题往下推一点,
|
||||
免得「孕期必用工具」直接贴到橙色头图底边上。 */
|
||||
免得「孕期必用工具」直接贴到橙色头图底边上。
|
||||
|
||||
⚠️⚠️ 2026-09-20:卡的显隐**要等 /letters 回来才算数**(lettersResolved)。
|
||||
之前的写法是「先把内置样例/本地队列拼出来的卡显示出来,数据回来再决定」——
|
||||
结果商城↔首页来回切时会闪一下:先冒出一张(甚至写着「宝宝回信啦」)的卡,
|
||||
几百毫秒后数据说没有未读,又缩回去。现在反过来:
|
||||
· index.html 里 #homeLetter 默认带 .hide、#homeBody 默认带 .no-letter;
|
||||
· 没确定(!lettersResolved)→ 一律保持收起;
|
||||
· 确定之后才可能显示,且只有在真有未读/新回信时才显示。
|
||||
代价是「有信」的用户看到卡出现在数据回来那一刻(晚一点点,但不闪)。 */
|
||||
let lettersResolved = false; // /letters 已经问过结果(含失败/访客态)—— 见 applyRemoteLetters
|
||||
|
||||
function hideLetterCard() {
|
||||
const card = $('#homeLetter'), body = $('#homeBody');
|
||||
if (card) { card.classList.add('hide'); card.classList.remove('has-new'); }
|
||||
if (body) body.classList.add('no-letter');
|
||||
}
|
||||
|
||||
function pushLatestToHome() {
|
||||
const card = $('#homeLetter');
|
||||
const body = $('#homeBody');
|
||||
/* 还没问出结果、访客态(没身份)、或后端明确说该用户没建档 —— 都别显示。
|
||||
⚠️ hashParam 是函数声明(在文件靠后定义),这里调用靠提升,没问题。 */
|
||||
if (!lettersResolved || !hashParam('openid') || state.pregEmpty) { hideLetterCard(); return; }
|
||||
const show = () => { card.classList.remove('hide'); body.classList.remove('no-letter'); };
|
||||
let msg = null, owner = null;
|
||||
LETTERS.forEach(L => L.thread.forEach(m => {
|
||||
@@ -3988,6 +4008,10 @@
|
||||
state.curLetter = ''; state.homeLetter = '';
|
||||
syncPregnancy(); /* 占位 + 隐藏脚印时间轴 + 信件引导态 */
|
||||
syncLetterCounts(); /* hero 计数切 '--'(角标 #tabBadge 已不由本地信件数驱动) */
|
||||
/* ⚠️ 必须重算首页来信卡:上面刚把 LETTERS 清空、pregEmpty 置真,
|
||||
不重算的话那张卡会停在「显示」状态,顶着一封已经不存在的信。 */
|
||||
lettersResolved = true;
|
||||
pushLatestToHome();
|
||||
return;
|
||||
}
|
||||
const base = '/api/mp/public/mama-box/';
|
||||
@@ -4119,14 +4143,22 @@
|
||||
拉不到 —— 无 openid / 接口挂 / 返回码不对 —— 就静默回落内置样例,页面照常可用。 */
|
||||
function applyRemoteLetters() {
|
||||
var openid = hashParam('openid');
|
||||
if (!openid) return;
|
||||
/* ⚠️ 下面每条**终态**都必须把 lettersResolved 置 true(含失败/无身份),
|
||||
否则首页那张来信卡会永远停在收起态(宁可收起也不能闪,见 pushLatestToHome)。
|
||||
无身份这条:卡本来就不该出现,置 true 只是让状态机收敛。 */
|
||||
if (!openid) { lettersResolved = true; pushLatestToHome(); return; }
|
||||
var base = '/api/mp/public/mama-box/';
|
||||
var j = function (u) { return fetch(u).then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; }); };
|
||||
j(base + 'letters?openid=' + encodeURIComponent(openid)).then(function (lj) {
|
||||
if (!lj || lj.code !== 200 || !lj.result || !lj.result.items) return;
|
||||
/* 拉不到(接口挂/断网/返回码不对)→ 静默回落内置样例。
|
||||
这**也是**一个终态:样板信照样要能上首页卡(离线可用),所以这里要置位并重算。 */
|
||||
if (!lj || lj.code !== 200 || !lj.result || !lj.result.items) {
|
||||
lettersResolved = true; pushLatestToHome(); return;
|
||||
}
|
||||
/* 新用户空态:后端成功返回空列表 → 清掉内置样例信,展示「这里还没有内容」。
|
||||
⚠️ 不能直接 return —— 那会把 LETTERS 留在内置样例上,新用户看到演示信。 */
|
||||
if (!lj.result.items.length) {
|
||||
lettersResolved = true;
|
||||
LETTERS.splice(0, LETTERS.length);
|
||||
state.curLetter = '';
|
||||
state.homeLetter = '';
|
||||
@@ -4155,12 +4187,13 @@
|
||||
LETTERS.splice(0, LETTERS.length, ...apiList);
|
||||
state.curLetter = LETTERS[0].id;
|
||||
state.homeLetter = LETTERS[0].id;
|
||||
lettersResolved = true;
|
||||
renderLetters();
|
||||
syncLetterCounts();
|
||||
pushLatestToHome();
|
||||
} catch (e) { /* 映射 / 渲染异常就回退内置样例 */ }
|
||||
}).catch(function () { /* 静默回退内置样例 */ });
|
||||
}).catch(function () { /* 静默回退内置样例 */ });
|
||||
}).catch(function () { lettersResolved = true; pushLatestToHome(); /* 静默回退内置样例 */ });
|
||||
}).catch(function () { lettersResolved = true; pushLatestToHome(); /* 静默回退内置样例 */ });
|
||||
}
|
||||
|
||||
/* ---------- 今日脚印(box_app → 数胎动对外 API,动态获取) ----------
|
||||
|
||||
Reference in New Issue
Block a user