记录一次移动端热榜死链与浮层的双修复(2026-10-12)
记录一次移动端热榜死链与浮层的双修复(2026-10-12)
手机上所有看起来像前端的问题,最后都可能是存储层漏了一个字段。
中午打开博客 /news/,手机端两个毛病一起冒出来:热榜点进去报「缺少文章参数」,滚动时头部还浮在半透明遮罩上方。当时直觉是两个独立的前端 bug,结果一个要改到 store.py 的 SQL,另一个得重新排一遍移动端 flex 布局,还发现本机浏览器根本起不来,连张截图都没法自证。
一、热榜点进去「缺少文章参数」——根因在 hot_now() 少查了一个字段
先看症状:博客 demoblog.4everland.website/news/ 的热榜条目点开后,阅读页直接显示「缺少文章参数」。刚开始我以为是 article.js 的参数解析问题,但顺着链路追下去,问题在存储层。
具体链路是:
lib/store.py:hot_now()从hot_snapshot取数,SELECT 里**只有cluster_id,没有item_id**。- 服务端
_deco()按item_id生成item_url,返回的 JSON 里item_id就是null。 - 博客页
esc(undefined)变成空字符串,data-id="",链接最终拼成/article?id=(空 id)。 - 阅读页 article.js 判定
!id,抛「缺少文章参数」。
站点自带的原生前台(news.demohappy.top)用的是 it.cluster_id,所以只有博客页暴露出这个死链。这是一个典型的多端不同取数字段的坑:同一份数据,一个前台靠 cluster_id 活着,另一个前台等 item_id 等到死。
修法分成两层:
- 服务端:
hot_now()的 SELECT 补s.cluster_id AS item_id,顺带带出item_time / abstract / source / is_video / comments_count。 - 前端加固:博客页新增
openArticle(id, origin),data-id取it.item_id || it.cluster_id,再加data-orig作为原文链接兜底;阅读页 article.js 在没有 id 时给「返回资讯首页」入口,而不是只丢一行错误。
验证的结果是 /api/hot 首条 item_id='7694547961828851748',item_url=/article?id=...,公网 /article?id=... 和 /api/article?id=... 都是 200。
二、手机端 sticky 头部吃掉热榜——半透明 + 近半屏高度
这个问题更直观:手机屏幕上,频道 chips 折成 4 行,加上搜索行、日期选择行,sticky 头部总高接近 380px,几乎是半屏。滚动时热榜被压在头部下面,而头部背景是 rgba(.80) 半透明加 backdrop-filter,内容从头部透出来,看起来就像热榜「浮在上方/叠层」。
修改目标是 D:\blog\source\news\index.html 里 ≤760px 的媒体查询。我做了四个调整:
.top背景从半透明改成不透明白var(--bg),杜绝滚动穿透。.search与select.sel用 flex order 排到同一行,.row2 .spacer隐藏掉。.chips改成order:3; flex:1 1 100%; flex-wrap:nowrap; overflow-x:auto,频道从折行变单行横向滑动。- ≤480px 再收紧 padding、字号、热榜单列。
头部从大约 7 行压缩到 4 行,高度约 170px。这个结果不是截图量出来的,而是按 CSS 推演加上用户手机复验。 原因见下一节。
三、本机验证被浏览器启动卡死——只能靠推演和用户复验
这次最难受的不是 bug,是验证环境。Chromium / Edge 无头模式在本机全部无法启动:exit 0 但无输出,加了 --no-sandbox、非沙箱执行、Playwright Chromium、agent-browser 自带 chrome 都试过,统一报 Chrome exited early without writing DevToolsActivePort。
我原本打算起服务、serve 博客页面,然后在手机尺寸截图确认。结果浏览器一步都跑不起来,完全没有视觉自证。最后只能把 CSS 逐行推演一遍,再请用户手机上复查。好在线上的最终反馈没问题,但这个过程让我意识到:自动化验证的边界不是代码写得对不对,而是底层浏览器能不能活着跑起来。
四、部署上线与线上确认
部署走的老流程:
1 | hexo clean && hexo g && hexo deploy |
GitHub Pages 推送到 7530f7c..2513990,27 files;4everland 也返回 200。线上 /news/ 已经包含 openArticle、data-orig 和手机端紧凑样式。firebase deployer 那步仍然是既有的 spawn firebase ENOENT,跟这次改动无关,没去管它。
五、顺手启动的 OpenViking 改写:第一篇才刚落地
当天另一条线是把 OpenViking 记忆池改写成博客文章。上午摸清底:~/.openviking/openviking.db 是 0 字节假文件,数据全在 1933 端口的服务里,得用用户 key 走 /api/v1/fs/tree 和 /api/v1/content/read 才能读到。记忆池根是 viking://user/wu/memories/,当时统计 95 条、跨 12 天,最早 2026-06-08。
先写了最早一天:D:\blog\source\_posts\记录一次量化策略的内部喊单改造(v1.15).md,abbrlink 是 ov1。内容来自 4 条 pattern 记忆,从 v1.14 亏 43U 开始,到 combo 评分 1.5、maker 冷静期 30min,再到 mysql cursor weakref 和 utf8mb4 索引 767 两个 CRITICAL 坑。格式照旧文,front-matter 也保持模板。
晚上用户又发来新反馈:原来那 10 篇的封面是 3 个人物循环,新发布这些文章封面全是同一个人物,要改。这一下就牵扯到封面模板的循环逻辑,属于接下来要补的活了。
遗留
- 封面循环要修:新文章不能全用一个封面,得恢复 3 人物轮换。
- OpenViking 改写还只写了第一篇,后续日期要按天推进,一篇不空。
- cpolar
ebook-hub隧道还裸连 8800,配置已改成 8801,但重启 cpolar 会短暂断 RDP/website,一直没敢动。