一句话:给「文章详情页」做了一套后台可配、前台可关闭的广告位系统 —— 一套配置管理三种广告形态,访客点 ✕ 就不再被打扰,且保证「先看见再消失」的闪烁和布局跳动都不会发生。
功能点
| 能力 | 说明 |
|---|---|
| 三种形态、三个位置 | 横幅(正文上方)、侧栏(矩形 300×250 或原生信息流二选一)、底部横条(正文/评论/相关阅读之后、页脚之前) |
| 一套内容配置驱动 | 全部在后台用一段 JSON 配:角标、图标、标题、描述、按钮文案+链接;原生版另有品牌名与头像 |
| 与旧广告互斥 | 后台一个下拉三选一:关闭 / 顶部广告卡片(原有那张)/ 广告位组合,从根上保证两套不会同时冒出来;默认值 = 原有行为,升级零风险 |
| 可关闭且「不闪不跳」 | ✕ 的关闭状态记在会话 cookie,由服务端渲染阶段直接判定是否输出 —— 不是「先画出来再藏起来」,所以既没有闪一下、也没有内容回跳 |
| 改内容 = 新广告 | cookie 名按「文案+链接」哈希生成,后台改了文案,广告对所有访客重新出现,不会出现「配了却不显示」 |
| 响应式 + 移动端适配 | 小屏按钮整行居中、关闭按钮常驻(触屏没有 hover) |
| 写入严格、渲染宽容 | 后台保存时不安全链接(如裸 #)直接拒存;前台遇到配错的槽位静默跳过,不会让文章页报错 |
访客实际能感知到的:广告长得像站内原生卡片(暖橙品牌色)、有关闭按钮、关掉之后刷新也不会再冒出来、手机上排版不挤。
这是设计如此的正常行为,不是故障 —— 点 ✕ 就等于「跟这条广告说再见」,它被记在浏览器 cookie 里,服务端下次直接不输出。
机制(三步)
| 步骤 | 发生了什么 |
|---|---|
| 1️⃣ 点 ✕ | 前端写一条 cookie:loveps-ad-banner-<hash>=1; path=/; samesite=lax |
| 2️⃣ 下次访问文章页 | 浏览器自动带上这条 cookie |
| 3️⃣ 服务端渲染 | adVisible(name) = !requestCookies.get(name)(article-detail.tsx:80)→ 服务端直接不渲染,不是前端藏起来 |
为什么用 cookie 而不是 localStorage:文章页是 SSR 的。cookie 服务端读得到,第一帧就没有它 —— 所以不会「先闪一下再消失」,也不会「消失后正文往上跳」。localStorage 只能等 hydration 之后隐藏,这两个毛病都躲不掉。
为什么刷新/换文章都没用:cookie 是 path=/(全站生效),且没写 max-age ⇒ 会话 cookie,关标签页、刷新都不清,只有彻底关浏览器才失效。另外它的名字是按「广告文案 + 链接」算的哈希(scope|title|desc|href),不含文章 ID —— 所以在任意一篇文章上关掉横幅,全站文章页的横幅都不再出现。
三个槽位互不干扰:banner / sticky / side 各有各的 cookie,关一个不影响另外两个。(第 96 次那张「文章顶部广告卡片」没有 ✕,不受影响。)
现在想让广告回来,任选其一
- 无痕窗口(最快):
Ctrl+Shift+N。 - 删掉该站 cookie:地址栏左侧的 🔒/⚙ 图标 → 「Cookie 和网站数据」→ 删除;或 F12 → Application → Cookies → 删掉
loveps-ad-开头的三条。 - 彻底退出 Chrome(关闭所有窗口,不是只关标签页)。⚠️ 如果你开了「继续浏览上次打开的网页」,会话 cookie 可能被一起恢复 —— 这种情况用前两种更稳。
- 在后台改一下广告文案或链接:哈希一变就是「一条新广告」,对所有访客重新出现(顺便也是验证配置改没改上去的土办法)。
如果你觉得这个行为不合适,可以改
- 改成「关一次记 1 天 / 7 天」:加个
max-age,比会话级更「记得住」(绝大多数站点是这个做法)。 - 改成「每篇文章独立」:cookie 名里拼上
article.id,在 A 文关掉不影响 B 文。 - 改成「只隐藏这一次」:不写 cookie、只
useState,刷新就回来 —— 但这样关闭基本没意义,我不推荐。



