改完设置下次还在:vibe 项目的设置页与偏好持久化实战
设置页就是产品的记忆。本篇给 vibe 项目一套三层偏好模型、存储组合策略和上线验收清单,让改过的设置换设备还在、升版本不丢。


用户最生气的一刻,往往不是产品缺功能,而是昨天刚调好的东西今天全没了。字体改回默认,提醒又响起来,工作区语言变回英文,连列表的排序都复位了。用户不会说“你们的持久化层有问题”,他只会说一句话:这产品不记得我。设置页就是产品的记忆,而记忆丢一次,信任就要花十次才能补回来。本文讲的,就是怎么把设置页做成一台靠谱的记忆机器:东西放在哪里找得到,改完之后下次还在,换了设备也能跟过来。
先说清楚本文的例子:文中出现的“青松笔记”和用户“林晚”均为虚构,只是为了把道理讲具体而编的例子,不是真实产品和真实用户。方法本身是通用的,放到任何一个 vibe 项目里都能直接套用。
先定一个观点:设置页不是杂物间,是产品的记忆
很多 vibe 项目的设置页是这样长出来的:今天加一个开关塞进去,明天加一个选项塞进去,三个月后变成一面贴满开关的墙。用户找“改密码”要翻三屏,找“导出数据”要先猜它属于哪个分组。问题不在于开关太多,而在于从来没有人给设置页立过结构。设置页的第一性原理只有一条:用户来这里是带着任务来的,他不是来参观的。他想改一个具体的东西,改完确认它生效了,然后离开。所有设计都要服务于这个流程,而不是展示你做了多少功能。
所以动工之前先做一道减法:把所有设置项列成清单,然后问三个问题。第一,这个设置用户一个月会碰几次?一年碰不到一次的,考虑收到更深的位置,或者干脆去掉。第二,这个设置改错了会不会伤人?会伤人的,后面要配确认和恢复手段,不能只是一个开关。第三,这个设置有没有默认值就能跑得很好?有的话,默认就应该是对的,不要逼用户先学会配置再使用。很多设置页的臃肿,都是把“开发者觉得可能有人要”当成了“用户真的需要”。
还有一个常见的误判:把设置页当成高级功能的陈列柜。真正好的设置页恰恰相反,它越安静越好。常用的三五项一眼可见,不常用的收进分组,危险的单独隔离。用户不需要在设置页里感受到产品的全部能力,他只需要在想改的时候一次改对。
三层偏好模型:先分清东西存在哪一层,再谈保存
偏好丢失有一半的原因不是代码写错了,而是从一开始就没分清:这个设置到底属于谁。我的建议是把所有偏好分成三层,写代码之前先给每一项定层,定完再动手。
第一层是设备偏好,只跟这台设备有关。比如界面字号、侧边栏收起还是展开、深色还是浅色跟随系统。这些设置换一台设备就不该跟过去,因为每台设备的屏幕和使用习惯都不一样。它们最适合存在本地,存在本地存储里,读写快,不依赖网络,离线也能用。硬要把它们同步到账号上,反而会在用户的新设备上制造惊喜:他在大屏上调大的字号,同步到手机上就显得巨大无比。
第二层是账号偏好,跟人走,不跟设备走。比如语言、时区、每周摘要要不要发、默认工作区。这些设置用户换了手机、换了电脑都希望还在,必须存在服务端,跟着账号走。只存在本地的账号偏好,是最常见的丢设置事故来源:用户清掉浏览器数据,或者换个浏览器登录,偏好就全没了,然后他会认定是产品把他的东西弄丢了。
第三层是工作区偏好,跟团队或项目走,不跟个人走。比如某个看板的默认视图、某个项目的提醒规则、某个共享文件夹的排序方式。这些设置改动会影响别人,存取时要带上工作区标识,改动时要考虑权限:不是每个成员都能改工作区级设置。把工作区偏好误写成个人偏好,两个人看到的同一个看板就会各说各话;把个人偏好误写成工作区偏好,一个人改字号,全组人的界面都跟着变。
定层的时候用一张决策表就够了:换设备要不要跟过去?跟过去就是账号层或工作区层,不跟就是设备层。改动会不会影响别人?会影响别人就是工作区层。两个问题答完,九成设置项的归属就定了。剩下那一成,比如“主题”这种两边都说得通的,定一条团队规矩统一处理,不要让不同的页面各写各的。
拿虚构的青松笔记走一遍这张表,结果会非常干净。林晚的字号和侧边栏状态是设备层,只存本地;她的语言、时区和每周摘要是账号层,存在服务端,换手机登录也在;她负责的那个共享看板的默认视图和提醒规则是工作区层,改动前要先看她有没有管理权限。最容易定错的是“默认新建笔记的模板”:它看起来像个人习惯,但如果模板属于共享工作区,改动就会影响同事,那就该算工作区层。定层会议上吵起来的项,往往就是这种边界项,吵清楚一次,后面所有页面都受益。还有一条补充规矩:同一项偏好在不同端表现可以不同,但归属只能有一个,比如手机端和电脑端都可以改语言,但语言只能属于账号层,不能在手机端存本地、在电脑端存服务端,否则两边迟早打架。
设置页的信息架构:分组、搜索和危险区
分层解决的是“存在哪里”,信息架构解决的是“找不找得到”。我推荐的分组方式是按任务分,不是按技术分。用户心里想的是“我要改外观”“我要管提醒”“我要处理账号”,他不会想“这个开关对应的是哪个后端模块”。所以分组名要用用户的语言:外观、提醒、账号与安全、数据、工作区,而不是配置、系统参数、高级选项这种开发者语言。
分组数量控制在五到七个。一个分组里的项目超过十个,就要再拆,或者把低频项收进“更多”里。每个分组的第一项,应该是这个分组里最常被改的那一项,因为用户点进分组的第一眼,就在判断自己有没有走错地方。分组之间不要有重叠的管辖权:同一个设置出现在两个分组里,用户改了一个地方,另一个地方没变,他会怀疑到底哪个才是真的。
设置项一多,就必须给设置页加搜索。搜索不是锦上添花,而是设置页长大后的必需品。搜索要搜得到设置的中文名、别名和分组名,用户搜“提醒”要能找到“通知”,搜“密码”要能找到“修改密码”。搜不到结果的时候,不要只显示一句“没有结果”,而要给出最接近的三个分组入口,并留一句话告诉用户可以去哪里反馈缺失的设置。空结果本身也是一种回答,写得好,用户就不会觉得是自己找错了地方。
危险操作要单独隔离,放在页面底部,用视觉上明显不同的区域装起来,比如带一条分隔线和红色标题的“危险区”。删除工作区、转让所有权、清空数据这类操作,绝对不能和普通开关混排在一起。混排的代价不是美观问题,而是误触概率:用户本来只想关一个提醒,手指一滑就点进了删除流程。危险区里的每一项,都要有自己的确认步骤,这个话题本系列另有专篇讲确认设计,这里只立一条规矩:危险操作离日常操作越远越好。
持久化四种机制:没有银弹,只有组合策略
偏好要真正“留下来”,靠的是存储机制的组合,而不是某一种技术的单打独斗。四种常见机制各有自己的位置,选错位置就是事故的种子。
本地存储适合设备偏好,优点是快、离线可用、不花服务器成本,缺点是清数据就没、换设备就没、容量有限。写本地偏好时要记住两件事:一是读写都要包一层容错,解析失败就回落到默认值,不要让一串损坏的数据把整个页面拖垮;二是不要把敏感信息放进本地存储,令牌和密钥不属于偏好,永远不要为了图方便塞进去。
服务端存储适合账号偏好和工作区偏好,优点是跟人走、换设备还在、可以做权限控制,缺点是依赖网络、要处理并发写入。一个常见的坑是“保存按钮假装成功了”:前端点了保存就显示成功,实际上请求还在路上,失败了也没人告诉用户。正确的做法是等到服务端确认后再显示成功状态,失败时明确告诉用户哪一项没存上,并保留他刚才的修改,让他可以一键重试,而不是让他重新填一遍。
地址栏参数适合那些“值得被分享”的偏好,比如当前视图、筛选条件、排序方式。它的好处是链接发给别人,对方打开就是同一个视图;坏处是地址栏不适合放太多东西,也不能放隐私内容。判断标准很简单:这个状态用户会不会想发给别人看?会,就放进地址栏;不会,就不要往地址栏里塞。
Cookie 适合少数需要在服务端渲染之前就知道的偏好,比如语言和主题,避免页面先闪一下默认主题再切换。但 Cookie 有大小限制,也不适合放复杂结构。把它当成“开场提示”,而不是偏好的主仓库。组合策略的口诀是:设备偏好放本地,账号偏好放服务端,可分享的状态放地址栏,首屏必需的放 Cookie。每一项偏好只认一个主仓库,其他地方可以有缓存,但缓存必须能被主仓库纠正,不能各自为政。
多设备同步与写冲突:后保存的不一定是对的
偏好一旦存在服务端,多设备同步的问题马上就会来。用户在手机上改了语言,在电脑上改了时区,两个请求先后到达服务端,如果处理方式是“后到的覆盖先到的整条记录”,就可能出现手机上的语言改动把电脑上的时区改动冲掉。这就是最常见的“改了一个,丢了另一个”事故。根因不是网络,而是保存的粒度太粗:整条记录覆盖,而不是按字段合并。
正确的做法是按字段保存、按字段合并。每个偏好字段独立更新,互不干扰。更进一步,可以给偏好记录加一个版本号,每次更新都带上自己读到的版本号,服务端发现版本号对不上,就说明中间有人改过,这时不要悄悄覆盖,而是把冲突的字段告诉用户,或者按事先定好的规则合并。版本号机制听起来重,但对于工作区级偏好几乎是必需的:两个人同时改同一个看板的默认视图,没有版本号,注定会互相覆盖。
还有一种更隐蔽的冲突:离线改动。用户在没网的时候改了设置,联网后才同步上来,这时服务端的偏好可能已经是新版。处理原则是先定优先级:离线改动是用户明确表达过的意图,一般不应该被静默丢弃;但如果离线改动和在线改动撞在同一个字段上,就要把两个值都摆出来让用户选,或者至少在同步完成后提示用户“有几项设置被更新了”。最糟糕的处理是悄悄选一个,然后假装什么都没发生。
同步状态本身也要可见。设置页的角落里,一个小小的“已同步”或“同步中”提示,就能省掉大量客服工单。用户最怕的不是等待,而是不知道自己的修改到底存上没有。同步失败时,提示要具体到字段:“语言已保存,提醒设置同步失败,点这里重试”,而不是一句笼统的“同步失败”。
默认值、迁移与回退:老用户的设置不能被新版本弄丢
偏好系统最容易被忽视的一环,是版本的变迁。新版本加了一个设置项,老用户第一次打开时它应该是什么值?删掉一个旧设置项,老用户原来存的值怎么办?改了一个设置项的取值范围,原来存的值不在新范围里了怎么办?这三个问题答不上来,上线当天就会有老用户来投诉“我的设置被重置了”。
我的三条纪律是:第一,新设置项必须有合理的默认值,而且默认值要站在大多数用户的立场上选,不是最保守的,也不是最花哨的。第二,旧设置项被删掉时,服务端的数据先保留一个版本,不要立刻物理删除,给回滚留余地。第三,取值范围变化时,写一段迁移代码,把旧值映射到最接近的新值,并在迁移日志里记下来。迁移代码要单独测试,尤其是边界值:原来存的是最大值,新范围缩小了,映射到哪里?原来存的是空值,新版本要求必填,默认填什么?
回退同样重要。保存失败、同步失败、迁移失败,都要有回退路径。前端乐观更新时,先把旧值留着,失败了就把界面恢复成旧值,并告诉用户恢复了。服务端写入失败时,不要留下半新半旧的记录,要么全写进去,要么全不写。用户可以接受一次明确的失败提示,他不能接受的是界面上显示成功、实际上数据已经乱了。
最后是“恢复默认”这个功能本身。每个分组都应该有一个恢复默认的入口,但恢复默认不是删除:执行前要列出会被改动的项,让用户确认;执行后要允许撤销,至少在当次会话里可以一键回到恢复之前的状态。没有撤销的恢复默认,和删除没有本质区别。
验收清单:上线前照着测一遍
把上面所有内容收成一张清单,发布前逐项打勾。第一,分层有没有定:每一项偏好都能说出自己属于设备层、账号层还是工作区层。第二,找不找得到:用五个真实任务测试设置页,比如改语言、关提醒、换主题、导出数据、删工作区,每个任务三步之内能不能完成。第三,保存可不可靠:断网保存、重复点击保存、两个设备同时保存,这三种情况有没有明确的反馈和正确的最终值。第四,换设备跟不跟得上:新设备登录后,账号偏好是不是都在,设备偏好是不是没有错误地跟过来。第五,老用户升不升级得起:旧版本数据导入新版本,有没有丢项、有没有错位。第六,危险区隔不隔离:危险操作是不是在独立区域、有没有确认步骤、有没有撤销路径。
再补三条容易漏的测试:清掉浏览器本地数据后重新登录,账号偏好是不是还在;把系统语言换掉,产品的语言偏好会不会被系统设置错误覆盖;两个人同时改同一个工作区偏好,最终结果是不是可解释的,而不是随机的。测完这张清单,设置页才算真正完成,而不是“看起来完成了”。
说到底,设置页的竞争力不在功能数量,而在可信度。用户愿意花时间调教一个产品,前提是他相信自己的调教不会白费。分层定清楚,存储选对地方,同步讲清冲突,迁移留好退路,设置页就会从“最容易被忽视的页面”变成“最让人安心的页面”。而安心,恰恰是用户留下来、继续用下去的理由。
评论 (0)
相关文章

确认设计不是弹窗数量,而是摩擦分级。本篇把危险操作分成四档、给每档配确认模式,并给出对象、后果、范围、出路四要素文案法。

点下收藏,就是立了一个“以后找得到”的约定。本指南讲收藏从模型到找回的完整设计:引用与快照、按钮三处反馈、合集排序搜索、失效内容、跨设备同步、游客合并、隐私默认与十项上线清单;示例产品与人物均为虚构。

翻页做错了不会在演示里出现,只会在真实数据量和真实使用路径下暴露。本指南把四种浏览模式对号入座到四种任务类型,讲清页码呈现、跳页、URL 分享、游标与偏移分页、无限滚动五大坑与十项上线清单;示例产品与人物均为虚构。