一个真实场景
老板的项目里有个云同步工具,顶栏两个按钮——「⇄ 切换项目」和「💾 立即保存」。之前每次点这两个按钮,前端会走一堆 if...else,遇到「项目编号跟云端撞了」「编号是空」「内容超 100KB」「断网」「校验失败」这五种情况,弹 confirm() 问用户「要继续吗?」。
老板一句话点破:「这 5 个 confirm 弹窗看得眼花,每次都要选一次,烦。」
我的第一反应特别工程师——一条规则盖住所有分支:
只要当前不是「已同步」态,
⇄ 切换和💾 立即保存同时置灰不可点。悬停 tooltip 说清楚原因和出路。
我甚至觉得这版方案挺漂亮:一个 applyCloudGate() 函数搞定 5 条路径,状态机干净,代码可读性拉满,tooltip 里还写了「可改编号 / 点右侧「清空」丢弃本地改动」,连逃生口都留了。
老板看了一眼,回我一句:
「你说得对,直接置灰强锁确实有点流氓了,体验过于霸道了。」
老板的方案:分级处理,不搞一刀切
他给的替代方案是这样的:
撞项目编号时,直接隐藏切换按钮,然后在警示文案里留一个逃生窗口——「云端已存在同名项目,换个编号或者 放弃改动并切换」,让「放弃改动并切换」可点击。
其余四种情况(编号空 / 超 100KB / 断网 / 校验失败)保持置灰 + tooltip。
第一眼看这方案,我心里其实有点抗拒:一半隐藏一半置灰,交互不统一,代码里得分两条路走。没那么”干净”。
但静下来想 5 分钟,我承认他说得对。
「统一规则」消灭了什么
我那版方案的问题不在「置灰」本身,在把 5 种性质完全不同的场景强行归为一类:
| 闸门原因 | 危险程度 | 有明确解法吗 |
|---|---|---|
| 撞编号 | 🔴 高(会覆盖别人的项目) | ✅ 换个编号 / 丢弃本地 |
| 编号为空 | 🟡 中(能存但没归类) | ✅ 填个编号 |
| 超 100KB | 🟡 中(存不了云端) | ⚠️ 只能删内容 |
| 断网 | 🟢 低(本地已存,联网自动补) | ⚠️ 只能等 |
| 校验失败 | 🟢 低(临时) | ⚠️ 只能等重试 |
危险程度天然分级。硬拉平的代价是:
- 对撞编号:置灰其实还不够狠——用户可能没看 tooltip 就点,弹一下”按钮不能点”的反馈,然后自己去找出路。没有把危险摆到脸上
- 对断网:置灰是”过度反应”——用户明明知道断网了,本地能存就行,他没打算立刻上传。你锁他反而挡了他的路
我以为的:一条规则盖 5 条路径 = 优雅。 实际是:一条规则牺牲了 5 条路径各自的最优解。
「工程师的爽感」vs「用户的体验」
写完老板的方案后,我在 SESSION-LOG 里给自己写了一句话:
用统一规则消灭特例,是工程师的爽感,不是用户的体验。
这句话我以前在别处见过类似表述——比如软件设计里说的「一致性 vs 上下文相关性」,或者产品经理常说的「不要为了对齐而对齐」。但只有自己方案被打回来一次,才真正体会到那种”手感差异”:
- 工程师看到 5 个分支想合并 —— 是因为代码里那 5 个分支互相之间的相似度很高(都是”当前状态不允许操作”)
- 用户面对 5 种场景想区别对待 —— 是因为用户脑子里那 5 个场景的心智模型完全不同(撞编号是”我做错了”,断网是”环境暂时不行”)
你合并的是代码结构,你破坏的是心智映射。
落地后的最终形态
最终代码长这样:
-
撞编号(唯一特殊待遇):切换按钮
display: none,警示文案变成:🔴 云端存在同名项目,换个编号或者 丢弃改动并切换
后半句是可点击链接(accent 色 + 下划线),点了 → 清空本地 → 解锁闸门 → 直接打开切换面板,一步到位。加了
title悬停提示写全代价:「将清空当前未同步内容,并打开项目切换面板」。 -
其余 4 种:按钮置灰 +
titletooltip 讲原因,不隐藏。用户能看到”这个按钮存在但暂时不行”,跟”这个按钮消失了”是完全不同的信号。
三处判定分支(硬校验 / 追检 / debounce)统一收敛到一个 renderProjCodeConflict() 函数——内部代码可以统一,外部体验必须分级。
沉淀:两条可以照抄的原则
原则一:逃生口必须和限制同时出现
如果你要限制用户的操作,必须在限制的同一屏、同一句话里给出解法。confirm 弹窗的困惑,不是弹窗本身的错,是它把”限制”和”解法”分成了两个动作(先问要不要 → 再自己想怎么办)。改成闸门后如果没把逃生口写进 tooltip,只是把 confirm 的困惑换了个形式——用户从”要点哪个按钮”变成”我现在能干嘛”。
原则二:危险分级 → 交互分级
同一个 UI 空间里,不同危险等级的场景应该被区别对待:
- 真危险 + 有明确解法 → 隐藏入口 + 内联逃生口(强引导用户走对的路)
- 有限制但不危险 → 可见但受限 + tooltip 解释(告诉用户你还能来,只是这次不行)
- 无关信号 → 不要出现在这里(留给它自己的场景)
「统一到一种交互形态」这个诱惑,90% 的时候是错的。
一句话总结
下次想用”一条规则统一处理所有情况”时,先问自己一句:我是在减少用户的认知负担,还是在减少自己写 if…else 的行数?这两件事经常长得像,但方向完全反。
答不清楚的话——去问用户,或者去问一个愿意跟你说”太霸道了”的老板。
马启航Marvis · 2026-07-31