分步表单的迷思
前提概要
出于历史原因,业务中出现了一种特殊的分步表单,既有步骤条的递进属性,也有 tab 的任意切换能力。但是经过实际的测试和验证后,发现这样的交互模式存在一些漏洞,而在已有的实现中,这些问题并没有得到解决,只是没有暴露或忽略了而已。
本文基于这个前提,整理了自己在分析过程中经历的一系列假设性思考,目的之一是为了说服产品和 UE 放弃这样的交互模式,之二则是通过梳理自己的思路,提高自身的逻辑能力,并为以后类似的问题提供参考和借鉴。
Step 和 Tab
step 和 tab 具有两种不同的交互方式。
step 是步骤条,表示用户需要按照预先设定好的步骤,按照流程依次往后执行一系列动作,隐藏的约束是,用户无法跳过某个步骤而进入它的下一个步骤。使用这种组件的场景一般是上一个步骤所操作的结果,会影响下一个步骤的交互,这种影响可能是业务上,也可能是交互上的。如果只是区分表单的内容,并不适合使用 step 组件。
tab 是可切换的导航,用户可以点击任意节点,切换到该节点所对应的 pane,所以 tab 和顺序无关,一般用来展示平级内容。
step 和 tab 的交互方式有着天然的冲突,对于表单设计,我们首先应该确定数据之间的关联性。如果数据有递进或者前后约束的影响,那么应该考虑使用 step 组件;如果数据之间没有明显的关系,更直接的设计是利用样式区分出不同区域的内容。
如果仅从交互层面来看,有没有可能结合这两个组件的核心特征呢?
结合两个组件
这里所讲的两个组件的结合,指的是既有 step 的步骤含义,也有 tab 的任意切换功能。在我们具体分析细节之前,先预设一下前提:
- 靠前的表单数据可能会级联地影响靠后表单的数据(或者校验规则);
- 靠后的表单数据不应该级联地影响靠前表单的数据(或者校验规则),不然这个分步的设计就有问题;
- 每个步骤下的表单都应该在校验通过后才能进入下一个步骤,否则这个分步骤的设计就不具有合理性;
在新建类型的表单中,初始化的状态下,按照 step 的特性,只有第一个步骤处于激活态,表示当前正在编辑该步骤下的表单,其它的节点是不可点击的。
这种设计和 tab 的任意切换特性有冲突,但可以通过禁用实现,如何实现禁用的逻辑是另一个课题。
如果想切换到下一个步骤,我们应该在完成表单后,点击「下一步」的按钮,这个按钮一般在表单的底部。
在点击「下一步」按钮时,需要对当前 step 对应的表单数据做一次合法性校验,校验的规则由业务决定,可能只是一些必填校验(同步),也可能需要和服务器交互确认输入数据是否正确的校验(异步)等,只有校验通过后,才能进入下一个 step。通过不断循环这样的交互,最终可以到达最后一个 step。
最后一个 step 仍然会验证数据,并整合所有分步表单的数据一起提交给服务器,这样就完成了一个分步表单的整个生命周期。这是分步表单最主线也是最简单的一套操作流,这套流程主要是将步骤条按照 step 组件的特性实现的。出于验证是否有可能结合 step 和 tab 的特征,我们接下来首先考虑一下能否通过顶部的 step 切换回上一个 step,或者之前已填写的任意 step?
步骤条的切换
如果允许点击切换,那么这会带来一个问题:是否需要验证当前 step 下表单的数据? 答案很显然,是不需要验证的。想象一个很常见的 case,用户填完其中的一个分步表单后,跳转到下一个表单,填写到一半,突然想起上一个步骤中填错了某个字段,或者想确认一下某个字段的值,那么我们自然需要允许他回退到那个表单中。这时,当前表单即使没填完,或者未通过验证,也是允许的。
[!tip] 缓存数据
这个未填写完成的表单数据,可以被"缓存"起来,方便下次再切换回来时,可以回显以便继续填写,这属于实现层面的内容,这里不多介绍。
现在用户已经切换到之前的某个已经验证通过的表单中,假设他修改了某个字段,然后打算返回到刚刚离开的 step。这里切换的方式有两种:点击底部的下一步按钮,或者点击顶部的 step 节点。
如果是通过点击「下一步」按钮,那么自然可以按照之前描述的那种交互策略,按顺序依次校验,最终成功地回到当初离开的那个 step 表单。而如果是通过点击顶部的 step 节点,就没那么简单了。
前面提到过,靠前的表单数据可能会影响靠后表单数据的校验,那么用户刚刚修改的那个字段,理论上来讲,是有可能导致后续表单的校验状态从正常变为失败的。如果这时候用户是直接切换回之前离开的 step 表单,就会跳过中间某个校验失败的步骤,这种情况下,只能拦截用户的切换操作,并重定向到这个验证失败的表单。可以想象这样的交互一定会造成很大的交互困扰。
那么有没有其它的解决或者兼容方案呢?
第一种可能的交互是,只允许往前跳转,不允许往后跳转。也就是通过顶部的步骤条切换表单时,只能切换回当前步骤前的、已经填写过的表单,而且一旦切换回去了,就不能再直接通过步骤条回到后面的表单。这样其实就是上面介绍的只能通过点击下一步按钮来完成所有表单的填写。
这种限制是可以解决问题的,不过会带来新的交互陷阱。如果一个用户想回头看(确认)一下之前填写的内容,但是当他通过步骤条切换回去后,发现再无法通过同样的交互方式还原到上一个状态时,一定会带来操作上的困惑。
另一种可能的交互是,放弃预设的前提,当用户跨步骤切换表单时,只验证当前离开的这个表单是否正确,跳过中间可以漏掉的表单,而是在最终保存的时候,再对数据做一次统一的校验。
这种方案也存在弊端。首先是验证时机的不统一会导致认知环混乱:正常流程下,用户点击下一步会校验表单数据,校验失败会阻止进入下一步,但通过跨步骤切换时却跳过了校验,改为了在最终提交前校验。其次,如果漏掉的步骤中有多个表单的校验出现问题,如何提示这些有问题的字段,也是一件麻烦的事情。
这些问题出现的根本原因是,当用户切换回靠前的某个分步表单时,排在该步骤之后的所有表单,都会变成一种不确定的状态了。这也说明了分步表单天然存在一种递进的关系,这种关系决定了在交互逻辑上,不能出现跳步。
所以我们不应该提供点击步骤条随意切换子表单的能力,那就需要在底部再添加一个「上一步」按钮,点击这个按钮可以回退到上一个步骤,同样,这样的切换也不需要验证当前分步表单的数据。
编辑和修改
我们再来看看编辑态下的交互。在编辑模式下,查询到的数据会回显到几个子表单中,这些数据是否一定是合法的呢?答案其实是不确定的。因为校验的规则完全因业务决定,比如某个时间字段需要在今天以后,新建的时候符合要求,编辑的时候(已经过了几天)可能就越过这个界限了。
所以在编辑模式下,分步表单也得按顺序依次执行到最后一步才能保证数据在提交前是完整可靠的。至于步骤条的点击切换操作,会存在和前面描述一样的问题,同样是不被允许的。
编辑模式下的表单,有一个前提是这个表单的数据是之前提交过的,那么无论现在的数据是否还合法,数据应该是存在的(不考虑后端或其它的逻辑修改数据),所以当用户打开一个编辑态的表单时,后续步骤的状态如果是和新建状态一样的灰色,那也会带来理解上的障碍:已经填写过,甚至大概率是正常的数据,为什么显示的是灰色?
解决这个疑虑的一种办法是:编辑态下表单,首先依据查询到的数据,对每个分步子表单做一次校验,并将校验结果显示在步骤条中,这样用户就可以通过步骤条的显示状态得知这个表单至少是有完整的数据。
假如某个子表单的校验没通过,是否需要将这种错误的状态表现在步骤条中呢?个人觉得可以根据实际的设计方案来决定,如果有设计错误的 step,那自然可以展示出来,如果没有,也不会有什么影响,因为用户只能通过点击下一步的操作,逐步完成整个表单的填写和修改,当他切换到有问题的表单时,自然会发现其中的某个字段不符合要求需要调整。
总结
根据以上的分析,我们基本可以得到以下几个结论:
- 由于 Step 和 Tab 天然的交互冲突,不适合在分步表单中结合使用;
- 分步表单只能通过「下一步」和「上一步」切换步骤;
- 编辑态下的分步表单,需要在初始化的时候执行一次校验;