LobeHub UX Audit 实战:以 Pages 模块审计为例,拆解「三层验证 + 模式回灌」的界面体验审查方法
【免费下载链接】lobehub🤯 LobeHub is your Chief Agent Operator, organizing your agents into 7×24 operations by hiring, scheduling, and reporting on your entire AI team.项目地址: https://gitcode.com/GitHub_Trending/lo/lobehub
LobeHub 仓库内置了一个可复用的 UX 审计技能(ux-audit),其基准是 Jennifer Tidwell《Designing Interfaces》的模式语言加上项目自有的ux执行检查清单。本文以该技能自带的真实工作样本——Pages 模块(/page文档列表 +/page/[id]全屏富文本编辑器)的 L1 静态审计为例,完整拆解一次审计如何从「模式识别 → 亮点固化 → 缺陷排序 → 规则回灌」闭环推进,读者读完后可以掌握一套可重复执行、证据可溯源的单页面 UX 审查方法论。
一、ux-audit 技能:一次只审一个表面,三层各自能"看见"什么
page.md是 ux-audit 技能 的references/example/目录下的一组工作样本之一(同目录还有channel.md、home.md、task-detail.md等 20 余篇)。技能定义的核心原则有两条:
- 一次只审一个表面(surface)——整站扫描对单次运行负担太重;每个页面在产品演进中反复重审,这才是"持续"的含义。
- 结论必须来自能看见该问题的层。审计分三层,每层有独立的操作文件:
| 层 | 操作文件 | 做什么 | 能抓到什么 | 成本 |
|---|---|---|---|---|
| L1 静态 | layer-1-static.md | 读代码 | 缺失的状态/分支(空态/错误/重试)、无草稿持久化、模式缺席、结构性问题 | 便宜、离线,每次审计必跑 |
| L2 视觉 | layer-2-visual.md | 对渲染后的表面截图 | 真实视觉层级与主控件、间距/对比/对齐、截断溢出、空态/加载/错误态的真实观感、响应式断点、暗色模式 | 中等,需要渲染环境 |
| L3 动态 | layer-3-dynamic.md | 通过 acceptance 框架驱动真实用户旅程 + 埋点 | 进行中/锁定态、强制触发的错误/空态、步骤衔接、焦点/键盘可达性、量化的 CLS/LCP/INP/长任务 | 高,需要运行环境 + 认证 |
技能的"覆盖矩阵"规定:例如"空态是否是一个真正的页面"是 L2 结论,不能由 L1 对着variant属性打勾;"两个 A/B 变体谁更好"更是 L3/分析层结论,L1/L2 只能比较机制差异,无权宣布胜者。
page.md的头部就如实标注了自己的审计状态,这是全文最值得学习的方法论姿态:
已运行层:L1(静态/代码)✅——以下全部。L2(视觉)/ L3(动态 + CLS)⏳ 尚未运行——见 §5。本文所有关于渲染的结论都是 L1 推断,等待 L2 确认。
同时它也声明了自己是模板而非现状真理("Use it as a template for the output shape, not as current-state truth (the code moves; re-verify before citing)")——代码在动,引用前必须重新验证。本文在复述各结论时,已按当前仓库代码重新核对了关键证据位置。
审计对象是文档编辑器类表面,对标 Notion / Google Docs / Craft。技能要求先给表面命名"类别(class)",写出该类别的领域惯例清单,再对照找差距——因为只读自家代码只能暴露"已经建出来的东西"的缺陷,对"根本没建的能力"在结构上是盲的。
被审计表面的核心文件(load-bearing files):
- 路由:
src/routes/(main)/page/{index,_layout,[id]}(入口 index.tsx/page/index.tsx) 用Suspense+SurfaceSkeleton包裹PageExplorerPlaceholder) - 侧边栏列表:
src/features/Pages/PageLayout/* - 空态占位:PageExplorerPlaceholder
- 编辑器 + Copilot + History + 编辑锁:
src/features/PageEditor/* - 状态:
src/store/page/*、src/store/document/slices/editor/* - 分享视图:
/share/page/[id](OSS 仓库中其错误/空态外壳是云构建的业务桩,见下文盲区说明)
二、§1 — 模式识别:这个表面用了哪些模式、用得好不好
L1 审计的第一步是把表面用到的界面模式对照 pattern-catalog.md 逐条列表评级。page.md的模式表完整如下(表格中的文件位置已按当前仓库结构给出):
| 模式(族) | 所在位置 | 评级 | 备注 |
|---|---|---|---|
| Overview + Detail(导航/数据) | 侧边栏列表 →/page/[id]编辑器 | ✅ | 保持上下文位置 |
| Deep-linking(导航) | /page/:id、/share/page/:id | ✅ | URL 可还原文档 |
| Empty-state as onboarding(增长) | 主舞台PageExplorerPlaceholder(新建/上传/Notion 卡片) | ✅ | 富 CTA——亮点 |
| 空态——侧边栏(数据) | PageEmpty.tsx | ⚠️ | 裸Empty,无 CTA(差距 ⑦) |
| Loading Skeleton(反馈) | Body+List的SkeletonList | ⚠️ | 存在但无法进入失败态(差距 ①) |
| Failure + Retry(反馈) | 列表 / 历史 / 保存 | — 缺席 | 该模块最大的系统性缺口(①②③④) |
| Autosave / Smart Defaults(输入) | performSave/performMetaSave、AutoSaveHint | ⚠️ | saving→saved,无 failed(差距 ②③) |
| Draft safety(编辑) | usePageDraft.ts(sessionStorage) | ⚠️ | 只在锁降级时做快照(差距 ②) |
| Entity lifecycle(操作) | 删除/重命名/复制/导出/历史恢复 | ✅⚠️ | Header 操作扎实;侧边栏操作静默(差距 ⑤) |
| Command History(操作) | History/*——列表 + Compare + Restore | ✅ | 有确认 + 进行中 + 错误 toast |
| Cancelability / lock(反馈) | EditingIndicator/LockedAlert/LockStatusBanner | ✅ | 三向、成熟——亮点 |
| Lists at scale(数据) | AllPagesDrawer(VList)+loadMoreDocuments | ⚠️ | 搜索只过滤已加载子集(差距 ⑥) |
| Modal Panel(导航) | Copilot / History 右侧面板(RightPanel) | ✅ | Copilot 复用共享 Conversation |
一句话读法(原文结论):编辑器的实体生命周期与协同锁是成熟的;弱点高度聚集在Feedback(失败态缺席、保存被吞成idle)与Read(加载失败伪装成空态;对部分列表做搜索)——与历次审计命中的软肋相同。
三、§2 — 亮点/优秀案例:重构时不许回退的清单
技能明确规定:只列缺陷的审计已经退化成 bug report。亮点是"回灌"循环的 ✅ 半区,是下一次重构的"不许回退"清单。Pages 审计认定了四个亮点:
- ✅ 亮点 — 三向协同编辑锁。
EditingIndicator/LockedAlert/LockStatusBanner构成一个成熟、可读的 presence/lock 模型:把"别人正在编辑"在三个高度上可视化,而不是一个不透明的标志位;这是模块里唯一把可取消性/并发端到端暴露出来的地方,重构必须保持三者同步。 - ✅ 亮点 — Command History 端到端暴露失败。
History/*(History/index.tsx)的列表 + Compare + Restore 带确认 + 进行中 + 错误 toast;是模块里唯一把失败态一路带到用户面前的流程(与差距 ②③④ 中被吞掉的保存/元数据/历史失败形成 ✅ 对照),这正是它"承重"的原因。 - ✅ 亮点 — Header 实体生命周期做对了(→ 已落地为 ux Act §3.1 的 ✅ 案例)。编辑器 Header 的删除/重命名/复制/导出/恢复中,复制操作做了 try/catch + 成功/错误
message(Header/useMenu.tsx)——与差距 ⑤ 里静默的侧边栏操作形成对照:同样的意图,这里变更能暴露自己的失败。 - ✅ 亮点 — 主舞台空态即引导。
PageExplorerPlaceholder(PageExplorerPlaceholder.tsx)的新建/上传/Notion 卡片把"无文档"状态变成了富 CTA,而不是死空间——增长侧"空态是起点"模式的规范实现(差距 ⑦ 的侧边栏空态是它的 ⚠️ 反例)。
四、§3 — 体验差距(按严重度排序)
技能的严重度标尺:🔴破坏信任(数据/输入丢失、永久卡死、误导性"空态"掩盖失败、静默发送失败);🟠死路或误导(无前进路径、状态含糊、缺进行中反馈);🟡摩擦/不一致/错失惊喜。以下 8 项差距 + 1 个盲区全部继承原文档,并对关键证据在当前仓库中重新定位。
① 侧边栏列表拉取失败 → 永久骨架屏 — Feedback §4.2 🔴
useFetchDocuments只在成功回调onData中写入documents(action.ts 中onData: (documents) => { ... internal_dispatchDocuments({ documents, type: 'setDocuments' }) }),而isDocumentsLoading = documents === undefined(selectors.ts 第 9 行)。Body在 loading 期间渲染SkeletonList。拉取出错时documents保持undefined→ 骨架屏永远转,没有错误、没有重试——这是典型的"初始化标志被成功回调门控"陷阱。
② 正文自动保存静默失败 + 草稿缺口 — Feedback §4.4 / Edit §2.1 🔴
performSave的 catch 分支中,非锁错误只把状态复位为saveStatus: 'idle'(action.ts 的catch块:仅CONFLICT置saveBlockedByLock,FORBIDDEN弹 toast,其余只console.error后回到idle)。状态枚举是idle | saving | saved,根本没有failed(initialState.ts 第 65 行)。只有CONFLICT(锁)会被表面化;网络错误/500 在用户看来与成功无法区分。同时isDirty保持 true,但 usePageDraft 只在锁不健康时才做快照——健康锁下的持续性保存失败既没有 failed 态、也没有草稿备份,刷新即静默丢失工作成果。
③ 元数据(标题/emoji)保存失败静默 — Feedback §4.4 🟠
PageEditor/store/action.ts 中performMetaSave的 catch 同样把metaSaveStatus复位为'idle'——再次没有failed。一次没持久化成功的标题/emoji 编辑,界面上看不出任何异常。
④ 历史加载失败伪装成"没有历史" — Read §1.1 🟠
History 的 SWR 解构只取了{ data, isLoading },丢掉了error(History/index.tsx);渲染逻辑是items.length === 0 ? <Empty "no history"/>。拉取失败 → 直接落到空态、无重试 → 用户会读到"这篇文档没有版本"这样的错误事实。
⑤ 侧边栏新建/重命名/复制静默失败 — Act §3.1 🟠
createNewPage出错时 rethrow(crud/action.ts),但调用方(AddButton、PageExplorerPlaceholder的新建入口)是 fire-and-forget——无 catch、无 toast;乐观插入的页面闪现一下就消失,还附带一个 unhandled rejection。侧边栏重命名(Editing)与复制(Item/useDropdownMenu)只有console.error。不一致之处:编辑器 Header 的复制做对了(try/catch + 成功/错误message,Header/useMenu.tsx)——同一意图,两套反馈行为。
⑥ "全部页面"搜索只过滤已加载子集 — Read §1.2 🟠
AllPagesDrawer 的Content用title/content.includes对allFilteredDocuments做客户端过滤,且滚动加载在搜索中会中止。500 篇页面只加载了 40 篇时,搜索一个未加载的页面会返回"无结果"——但它是存在的:一个假空态(分页排序必须走服务端规则的读侧孪生问题)。
⑦ 侧边栏空态没有 CTA — Read §1.1 🟡
PageEmpty.tsx只渲染一段描述(它确实区分了"没有页面"与"搜索无匹配"——这点做得好),但缺少"创建你的第一页"动作;富 CTA 只存在于主舞台占位符中,侧边栏空态因此是一个安静的死胡同。
⑧ 硬编码英文字符串 — i18n 🟡
PageExplorerPlaceholder中直接渲染了字面量'Uploading...',而不是走t()国际化 key——多语言用户会看到英文残留。
⏳ 盲区:分享视图的错误/空态是云构建桩 — 无法在 OSS 仓库审计
分享视图把数据与错误交给业务外壳渲染,而 OSS 仓库里的 PublishedShell.tsx 忽略data/error直接返回{children},所以一个失败/不存在的分享链接会渲染空白。真实行为在业务包(cloud build)里——只能留待 L2/L3 在云构建上确认。原文档明确把这一点列为"盲点"而不是"缺陷",正是"证据边界"规则的体现:L1 在 OSS 仓库里看不见它的真实状态。
五、§4 — 技能反馈:审计如何回灌ux检查清单
page.md的第四节记录了一次审计如何反哺技能体系("回灌"循环)——这是整个方法论"持续"的关键:
- 新增/强化落地的
ux条目:- Feedback§4.4— 新增检查清单行 + PageEditor ❌ 案例:保存状态枚举必须能够表示失败;
catch里复位到idle是把静默写入烧进类型的陷阱(差距 ②③)。 - Act§3.1— 新增"乐观变更必须暴露失败"规则 + ❌(侧边栏新建/重命名/复制)vs ✅(Header 复制)对照案例(差距 ⑤)。
- Read§1.2— 新增"对分页列表的搜索必须查询服务端全量"规则,
AllPagesDrawer作为 ❌ 案例(差距 ⑥)。 - 每条同步镜像进 SKILL.md 的 Quick review。
- Feedback§4.4— 新增检查清单行 + PageEditor ❌ 案例:保存状态枚举必须能够表示失败;
- 验证了既有规则(提供了好的 ❌ 引用案例):§4.2 永久骨架屏(差距 ①)、Read §1.1 空态 vs 失败(差距 ④)、Read §1.1 空态需要 CTA(差距 ⑦)。
技能文档强调:ux是审计的度量基准,审计是让ux保持诚实的机制——每次运行结束前必须完成"落地"三步:修掉最严重的 🔴 或建单、把可泛化差距回灌成检查清单条目(含 ✅/❌ 案例 + Quick review 镜像行)、把审计本身存为references/example/<page>.md供下次复用。如果一次运行真的没有可泛化的差距,也要在报告里明确写出来——沉默不是合法的收尾。
六、§5 — 待办:L2 视觉 + L3 动态
page.md明确声明本次是 L1-only,并在文末列出了后续必须执行的确认项——这示范了"结论只声明自己证据层能支撑的部分":
L2(视觉)——确认:侧边栏空态(PageEmpty)的真实观感(死空间还是页面感);Copilot / History 右侧面板布局;编辑器单一主操作是否清晰;占位符卡片在窄屏与暗色模式下的表现。
L3(动态)——逐项强制故障来证实差距:
- 列表拉取离线 →实时确认差距 ①(永久骨架屏、无重试);
- 健康锁下强制保存 500 →确认差距 ②(静默"看起来成功"态、无草稿 → 刷新丢工作成果);
- 强制历史拉取报错 →确认差距 ④(显示"没有历史");
- 驱动新建/重命名/复制失败 →确认差距 ⑤(条目消失、无 toast);
- 在全部页面抽屉中搜索一个未加载的页面 →确认差距 ⑥(假空态);
- 测量骨架屏→内容切换与 Copilot 挂载过程中的编辑器 CLS/LCP。
七、从这篇工作样本能学到什么
page.md的价值不在"Pages 模块有 8 个缺陷"这个结论本身,而在于它展示了可复制的审计形状:
- 先声明审计层与盲区(L1 已跑 / L2、L3 未跑 / 云构建桩不可见),每个结论都挂在它能被"看见"的层上;
- 模式表 + 亮点 + 差距三件套:亮点与差距对等成文,
file:line级证据,亮点直接变成检查清单的 ✅ 案例与重构回退保护线; - 差距按严重度排序并标注违反的具体清单条目(Feedback §4.2、Read §1.1 等),使每个发现可独立检索、可验证;
- 回灌闭环:可泛化的差距成为新的规则 + ❌ 案例,优秀实现反过来 sharpen 规则文本——审计跑完,检查清单比跑之前更锋利;
- 待办即承诺:L2/L3 的强制故障脚本写清楚,下一轮审计可以从这份清单直接续跑。
在 LobeHub 仓库中,这套样本与 ux-audit 技能定义、三层操作文件(L1 / L2 / L3)以及references/example/下的其他模块样本共同构成了一套"以证据而非感觉"的界面体验治理流程;而本文所引的全部代码证据(src/store/page、src/store/document/slices/editor、src/features/PageEditor、src/features/Pages/PageLayout)都可以按文中路径直接在当前仓库中复核——这正是该技能反复要求的:引用之前,重新验证。
【免费下载链接】lobehub🤯 LobeHub is your Chief Agent Operator, organizing your agents into 7×24 operations by hiring, scheduling, and reporting on your entire AI team.项目地址: https://gitcode.com/GitHub_Trending/lo/lobehub
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考