去年我在评审一个App登录页的高保真设计稿时,被开发当面问住了:“邮箱没填,点登录怎么办?”“密码少于6位,提示什么?”“账号密码不匹配,是弹Toast还是整页报错?”我翻着稿子,发现错误状态页其实都画了,但它们之间没有形成一条可以验证的交互链路。从那以后,我开始用Figma做“登录条件验证”原型,不是画完页面就交差,而是把输入、校验规则、分支提示全部用原生交互能力连起来。Figma不需要装第三方插件,自带的Variables和条件连线就能搞定这件事。这篇文章就是想把我的拆解方法和实操步骤完整写出来,给正在做登录模块交互稿的设计师和产品经理一个可以直接照搬的思路。
1. 登录逻辑怎么拆:条件验证到底在验证什么
很多设计稿只画了“登录页”“登录成功页”“登录失败页”三张界面,评审时被追问细节才发现漏了一堆分支。做条件验证原型的第一步,根本不是打开Figma拖画板,而是先把登录流程里的条件穷举出来。
1.1 先列全“用户可能做错的所有事”
登录场景下,用户能犯的错其实非常有限,我习惯把所有可能性列成一张清单:
- 邮箱或手机号为空
- 密码为空
- 邮箱格式不对(缺少@、缺少域名后缀、首尾带空格)
- 手机号位数不对,或中间混入字母
- 密码长度不足(通常产品会规定最少6位或8位)
- 账号密码不匹配,登录接口返回失败
- 网络超时或服务器异常
- 用户在等待结果时连续点击登录按钮
这里有一个设计师最容易忽略的坑:很多人只做“填对了”和“填错了”两种状态,但实际交互里需要的是四类状态——默认、输入中、校验错误、提交中,然后再叠加上“校验通过”和“登录成功”的后续分支。也就是说,一个看起来简单的登录页,在交互层面至少有6种以上可以被观察和验证的状态。
1.2 用一张状态-事件表把分支固定下来
我推荐在动笔设计前,先画一张“状态-事件表”,把触发条件和对应结果固定住,后面连交互时就不会东漏一条西漏一条。
我常用的一张登录条件验证表大致长这样:
| 触发事件 | 当前条件 | 结果状态 | 提示文案与行为 |
|---|---|---|---|
| 点击登录 | 邮箱为空 | 邮箱输入框错误态 | 显示“请输入邮箱/手机号” |
| 点击登录 | 密码为空 | 密码输入框错误态 | 显示“请输入密码” |
| 点击登录 | 邮箱不含@或不含. | 邮箱输入框错误态 | 显示“邮箱格式不正确” |
| 点击登录 | 手机号不为11位 | 手机号输入框错误态 | 显示“手机号应为11位数字” |
| 点击登录 | 密码长度小于6 | 密码输入框错误态 | 显示“密码至少6位” |
| 点击登录 | 账号或密码与预设不符 | 表单顶部错误条 | 显示“账号或密码错误” |
| 点击登录 | 账号密码匹配 | 按钮加载态→成功页 | 加载1.2秒后跳转 |
| 提交过程中 | 用户再次点击按钮 | 按钮保持禁用 | 忽略重复点击 |
这张表一定要和交互稿放在同一个Figma页面里。我通常把它放在画板最上方,用注释块锁住。因为评审时产品、开发、测试都在看同一个文件,表格比口头解释严谨得多,也方便测试同学照着写用例。
2. 用变量和变体给登录框装上一个“隐形大脑”
条件验证在Figma里能落地,依赖两个核心能力:Variables(变量)和Component Properties(组件属性)。前者用来记录“当前输入了什么”“校验结果是什么”,后者用来让输入框、按钮、错误提示根据变量值自动切换外观。
2.1 变量系统里要建哪些东西
打开Figma右侧的Variables面板,新建一个Collection,我建议命名为login_check,然后在这个集合里建下面这些基础变量:
| 变量名 | 类型 | 初始值 | 用途 |
|---|---|---|---|
| emailInput | String | 空字符串 | 记录邮箱/手机号输入框当前内容 |
| passwordInput | String | 空字符串 | 记录密码框当前内容 |
| isEmailEmpty | Boolean | true | 邮箱是否为空 |
| isPasswordEmpty | Boolean | true | 密码是否为空 |
| isEmailFormatOk | Boolean | true | 邮箱格式是否通过 |
| isPasswordLengthOk | Boolean | true | 密码长度是否通过 |
| isLoginSuccess | Boolean | false | 登录结果是否成功 |
| isSubmitting | Boolean | false | 是否处于提交中状态 |
| demoEmail | String | admin@demo.com | 预设的合法演示账号 |
| demoPassword | String | 123456 | 预设的合法演示密码 |
变量命名我强烈建议加前缀,比如login/emailInput或login/开头的分组。真实项目里登录、注册、找回密码三个流程在同一文件时,变量一多,不加前缀根本分不清哪个属于哪个流程。
这里要注意一个点:demoEmail和demoPassword这种“预设常量”,不是为了造假,而是为了让评审时可以重复演示“输入正确账号→成功”和“输入错误账号→失败”两条路径。没有预设值,演示成功态就只能靠运气。
2.2 输入框组件状态怎么做
设计稿里一个输入框,通常有默认态、聚焦态、填写态、错误态。我建议把它们做成一个组件集(Component Set),属性定义为state,四个取值分别是default、focus、filled、error。
在Figma里把输入框包进组件集之后,选中属性面板里的state,点击右侧的“绑定变量”图标,把它绑定到对应的布尔变量上。比如邮箱输入框的error状态,就绑定isEmailFormatOk == false或isEmailEmpty == true。这样当变量值改变时,输入框的外观会跟着自动切换,不需要手动跳转到另一个画板。
错误提示文案我一般不硬编码在变体里,而是用一个文本变量或实例属性来承载。原因很简单:评审时产品经理很可能说“提示文案改成‘账号不存在’”,如果文案散落在多个变体内部,改动量会让人崩溃;做成属性后,只需要改一个地方。
2.3 不要忽略“启动时先重置”
这个坑我踩了很久才反应过来。Figma的变量在一次演示会话里是有记忆的,假设你上一轮演示时输入了错误密码,isLoginSuccess已经是false,输入框停留在错误态。你退出预览,重新进入,如果不做任何处理,这些变量仍然是上一次的残留值,界面看起来就像“什么都没干,错误提示一直挂着”。
解决办法是在第一个画板(登录页)上增加一个On load交互,把所有状态变量一次性重置:emailInput设为空,isEmailEmpty设为true,isPasswordEmpty设为true,isLoginSuccess设为false,isSubmitting设为false。这个动作很小,但直接影响演示体验。没有这个重置步骤,你给领导演示时很容易翻车。
3. 核心交互链路:空值、格式、结果三类分支怎么连线
做完了变量和组件状态,接下来就是把它们“串”起来。Figma里条件验证的核心交互都发生在“登录按钮”到“各个结果状态”之间的连线上。选中登录按钮,在Prototype面板新建交互,Trigger选择On click,然后往目标画板或组件上拖出一条连线,点击连线中点的条件标记,就可以配置判断逻辑。
3.1 空值校验:优先级最高的一刀
空值校验是整个校验链路里优先级最高的分支,因为它不需要判断格式,只要判断“有没有内容”。我通常会画两条条件连线,放在整个交互列表的最前面:
- 如果
isEmailEmpty为true,进入邮箱错误提示状态 - 如果
isPasswordEmpty为true,进入密码错误提示状态
Figma的条件连线是顺序匹配的,预览时会从上到下逐条检查,匹配到哪条就执行哪条。所以一定要把空值判断放在最前面,一旦放在格式判断后面,就会出现“邮箱明明没填,却被提示格式错误”的滑稽结果。
这里有一个你可能没注意到的细节:空值判断有两个时机。第一个时机是用户点击登录按钮时,这个直接判断变量即可;第二个时机是用户从空值状态修改输入后,错误提示是否立即消失。我一般会在输入框的On click或On focus交互里加一步“清除对应错误状态”的动作,让用户一重新输入,红色边框马上消失,而不是等下一次点击登录才刷新。
3.2 格式校验:Figma里没有正则,就用条件和常量模拟
很多设计师以为Figma能做正则校验,其实它的条件逻辑里没有正则引擎。但这不是问题,因为在原型演示中,我们只需要模拟出“规则判断”这个行为本身。
我的做法是把格式校验拆成两个可判断的规则:
- 邮箱格式:判断
emailInput是否包含@且包含. - 密码长度:判断
passwordInput的字符长度是否大于等于6
Figma的条件编辑器支持文本运算,比如contains、does not contain、length。所以在“点击登录”交互中,我加两条条件连线:
- 条件组:
emailInput不包含@或emailInput不包含.时,进入邮箱格式错误提示 - 条件组:
passwordInput长度小于6时,进入密码长度错误提示
至于账号密码匹配,那就更简单了。把条件写成“emailInput等于demoEmail且passwordInput等于demoPassword”,满足就跳转成功页,不满足就进入登录失败提示。
在实际Figma操作里,条件编辑器右下角有Add condition和Add group按钮,多个条件之间可以选择And或Or,用组合条件完全可以承载上述逻辑。
3.3 登录结果分支:成功、失败与加载态三态转换
登录按钮点击后不能瞬间跳到结果页,否则演示效果假得离谱。我习惯的流程是:点击登录后,先通过Set variable动作把isSubmitting设为true,按钮组件绑定这个变量后自动切换到加载态,同时禁用点击;然后利用Figma的After delay触发器,延时1.2秒后再执行条件判断。
延时后的条件判断,就是整个登录验证链路的“终点分叉”:
- 条件满足:
emailInput等于demoEmail且passwordInput等于demoPassword,跳转到登录成功页 - 条件不满足:跳回当前登录页,同时把页面顶部的错误条组件状态改为“显示”,展示“账号或密码错误”
这里有个细节:失败后不要跳到另一个画板再跳回来,那样会有明显的闪屏。把整个登录表单做成一个组件,失败后通过组件实例的属性切换,在原地把错误状态渲染出来,体验会顺滑很多。
另外,延时判断时要用isSubmitting作为前置条件,避免用户快速双击产生两次跳转判断。配合按钮加载态的视觉反馈,这套三态转换在评审时基本能应对所有提问。
4. 演示体验升级:错误提示、键盘、防重复点击
条件验证的逻辑跑通之后,原型的“可用性”有了,但“演示感”还不够。评审会上,打动人的往往是那些不明显的细节:错误提示怎么弹出来、按钮加载时什么状态、手机键盘有没有遮挡输入框。这些细节不需要花很多时间,但做好了,整个原型会从“能用”变成“像真的”。
4.1 用 Smart Animate 做错误提示的进出场
Figma的Smart Animate是我做错误提示的首选动画方式。前提是:错误提示文本的图层名称,在默认态和错误态两个画板或组件变体中保持一致。
比如邮箱错误提示“请输入邮箱/手机号”这个文本图层,在默认态我把它设为透明度0、往下偏移4像素;在错误态设为透明度1、偏移0像素。两个状态之间用Smart Animate过渡,动画时长设为150毫秒,缓动选Ease Out,看起来就像错误文案从下方轻轻浮上来。
底部错误条的弹入,我用的是高度或y轴位移的变化,类似从屏幕顶部滑下来。这里切记不要用Dissolve交叉溶解,因为文案变动时会有残影,视觉上很脏。
4.2 移动端键盘避让与安全区问题
如果你做的登录页带手机壳预览,那键盘遮住输入框的问题几乎一定会被问到。但Figma原生原型对键盘弹起的支持非常有限,它不会真的模拟软键盘。我的处理方式是:把键盘交互单独拆一帧来说明。
具体做法是:在登录页旁边放一个“键盘状态参考画板”,将页面整体上移120像素,模拟键盘弹出后的避让效果,再用一个箭头注释说明“此时输入框已被键盘覆盖,页面需要整体上移”。这样开发和产品一眼就明白意图,等真正开发时按移动端键盘避让规范处理即可。
安全区的问题则直接在设计稿里规避:登录主按钮距离底部至少保留34像素的Home Indicator安全距离,输入框也不要贴到屏幕边缘。Figma里可以直接用Auto Layout的固定间距控制,不需要单独做变量。
4.3 防重复提交的加载态处理
登录按钮的加载态,本质是一个组件属性切换问题。把按钮做成一个组件集,属性isLoading设为Boolean,false时显示“登录”文字,true时显示一个旋转的Loading图标并禁用点击。
我在按钮组件内部绑定isSubmitting变量后,点击登录按钮时执行两个动作:先Set variable isSubmitting = true,再启动延时1.2秒的后续判断。这样按钮会在点击瞬间进入加载态,等条件判断结束,再把变量改回false。整个过程不需要单独跳转到“加载页”,按钮自身就能完成状态闭环。
这个细节在演示时非常加分。因为产品经理和开发经常问“用户网络慢,双击了怎么办”,你直接在原型里演示一遍“第一次点击按钮变灰转圈,第二次点击无效”,比任何口头解释都管用。
5. 发布评审时最容易翻车的细节与我的处理习惯
条件验证原型做到能演示,并不代表它经得起评审。我把这个原型在项目里跑了三个版本,踩过不少坑,也总结了一套固定的检查流程。
5.1 评审时最常被追问的三个逻辑缺口
我整理了一个高频追问清单,你在发布前可以对着自查:
| 追问 | 问题本质 | 我的解决办法 |
|---|---|---|
| 清空输入后再点登录,提示会恢复吗? | 缺少输入变更时的状态重置 | 在输入框交互中增加“清空错误变量”动作 |
| 密码错误和账号不存在是同一个提示吗? | 业务规则未细化 | 条件表里单独拆出账号不存在分支,或与密码错误合并 |
| 从“忘记密码”页返回登录页,错误提示还在吗? | 变量未在页面切换时重置 | 在“返回登录页”的交互前增加变量初始化动作 |
这三个问题我几乎每一次评审都会被问到。其实前两个在设计阶段就能通过条件表规避,第三个则是变量作用域没有设计好导致的。
5.2 变量作用域与多页面复用的坑
Figma变量的作用域层级是:Collection(集合)→ Mode(模式)→ 局部覆盖。登录、注册、找回密码几个流程如果放在同一个Collection里,所有页面都能读取同一份变量,这是正确的做法。但如果某个Frame或Group上覆盖了局部变量,或者你在复制组件时不小心带出了旧的变量绑定,预览时就会出现“登录页改了变量,注册页不生效”的诡异问题。
我现在的习惯是:所有登录验证相关的变量集中放在一个Collection,不单独给某个Frame设置局部变量。一旦发现某个组件实例的属性绑定变成了“未链接”状态,立刻重新绑定到Collection里的全局变量上。排查方法很简单:选中异常组件,看属性面板右侧有没有绑定图标,没有就说明丢了。
另外,从团队协作的角度,这个Collection最好发布为Library资源。因为登录验证逻辑在整个项目里往往不止一个页面使用,发布后其他成员可以直接复用这套变量定义,而不是各自建一套。
5.3 条件表当注释:复盘后我保留的工作习惯
跑完整个流程,我现在做登录类需求时,固定动作是先建条件表,再建变量,最后才画界面。条件表放在Figma页面最顶部,锁定后当作需求注释使用。每次更新原型,我就同步更新这张表,确保表和交互永远一致。
如果你刚开始接触Figma的变量和条件逻辑,不要一上来就做完整的三端适配,先用一个登录页把空值、格式、结果三条链路跑通,体会一下“变量驱动界面状态”的感觉。等这个流程熟练了,你会发现它不仅适用于登录验证,凡是涉及表单校验、多步骤流程、权限判断的场景,这套方法都能复用。到时候,你画的就不再是几张静态页面,而是一个“会思考”的产品原型了。