美文网首页
小程序表单动态配置与表单联动 - 实现篇

小程序表单动态配置与表单联动 - 实现篇

作者: 前端C罗 | 来源:发表于2021-02-20 14:21 被阅读0次

    表单(form)是用户填写(输入)信息的重要交互UI元素,所有需要收集信息的页面均会使用到表单。

    表单在桌面应用、app、web应用、小程序等均被广泛应用,各个平台上开发表单相关的功能在实现上也会有些不同,而对于表单的配置、联动也是很多开发者需要面临并尝试解决的难题。

    在微保小程序的年金产品投保模块,也涉及到表单的相关处理,有些自己理解,抛出来大家一起讨论。
    先看一张报价区域表单信息的截图,这是一个比较常见的投保报价表单模块。


    报价模块表单截图

    从图中可以直观看出,表单模块的一些特点:

    • 表单语义鲜明
    • 控件复用
    • 多状态(preview、edit)可并存、切换

    语义鲜明是报价表单模块较为突出的特性,用户的报价是要基于这些语义项的值,意味着表单组件要能够承担起内部控件数据向语义准确的请求数据转换的职责。页面初始化及用户通过操作控件带来的数据变化要能够被包装成固定格式的request data
    就像是一个完整的采购-加工-输出的流程

    流程类比图

    笔者认为要解决表单模块的配置化、表单联动需要解决下列问题

    • 表单描述
    • 联动机制
    • 表单更新
    • 数据维护

    围绕上述4个问题,笔者将会介绍在小程序环境下如何实现投保模块表单的配置、更新、数据维护、联动。

    表单数据与视图

    整个表单的配置化与显示是数据到视图的映射,因此数据、模板是表单的重要组成部分

    表单组成
    表单对应的配置数据笔者使用json格式,在对表单进行配置之前,将表单模块进行分层。表单可以拆解到表单项,进而再进一步拆解到控件,先一起看看下图的拆解。 表单项

    从图中可以看出,一个完整的表单模块可能是有N(N >= 1)个表单项,很多复杂的表单模块甚至有多层嵌套;同时,每个表单项有自己清晰的标题用以说明此项的业务含义、有明确的表单项状态(编辑态、预览态、隐藏或显示)、有自封闭的控件完成用户相关的信息输入。

    进一步抽象出相应的配置如下


    表单数据抽象结构

    对上述的脑图进行一些说明

    • 配置参数&业务数据,一份是自身转换为视图的配置数据,通常会由外部设置;一份是业务数据,初始化时由外部传入,后续表单项自己根据自身控件的变化或其他表单项的控件变化触发,修改相应的数据。
    • 控件参数,外部传入配置数据时,将表单项的控件数据抽象为json对象的格式,这样做有个很大的好处就是从表单项层面,是可以完全统一的,不用具体关注表单项内部的控件具体是张三还是李四。
    • 触发器,后续为实现表单联动设计的属性,是个字符串数组,值为配置参数的name子集。
    • 行为,同样为表单联动设计新增的属性,实际是一段js脚本,设计为监听到触发条件达到时动态执行,脚本的目标是完成联动时对自身的更新。

    整个流程涉及到配置服务、控件开发、表单组件封装、表单模块数据维护等。视图的呈现使用数据驱动,而表单内部的变动会以自定义事件的形式抛出,表单内部的联动使用发布-订阅的方案。
    为了适配业务的诉求、控件复用,对整个表单组件进行分层,如下图所示

    Form组件分层
    上层Form组件以事件冒泡的形式,抛出update的事件,供业务方监听处理,同时对外提供初始化,状态获取,更新视图等接口。相应的类图如下:
    分层类图

    控件均从抽象基类派生,需要实现相应的抽象方法,控件作为用户实际操作的交互单元,整个表单模块对其的状态变更和数据获取需要能非常便捷触达。同时,受益于整个架构的分层,控件的引入可以自己开发、也可以引入第三方的控件库,只需要做少量的适配工作即可。

    表单联动

    简单理解就是不同的表单行(联动的粒度是表单行)之间存在制约关系,一个表单行的值会影响其他若干表单行的值域、状态、显示与隐藏。
    配置数据通过初始化驱动表单视图显示,用户打开此视图后,会根据实际情况、个人喜好操作表单,由此导致相应的数据值发生变化。即使是同类型但不同的保险公司推出的保险产品,其受限规则可能都是不同的。
    但不管是哪种情况,表单联动要解决的核心问题有2个

    • 关注的变化
    • 响应的动作

    为解决这2个问题,配置中引入triggersaction的概念。整个模型基于事件总线和event loop机制,用户操作会触发控件的change事件,表单行捕获change事件,通过数据包装,在总线上广播自身变动的事件,监听相关事件的表单行,执行action中下发的js脚本

    联动机制
    整个机制完全的配置化有一个绕不过的问题,那就是如何执行下发的js脚本
    众所周知,小程序不支持eval执行脚本代码字符串,但可以通过引入或实现js解析与执行的引擎来解决此问题。
    整个流程如下图: 实现js简易引擎的流程

    社区中有比较成熟稳定的AST生成库,比如acornbabylon等,开发者可以在此基础上实现解释器即可完成目标。感兴趣的读者可以参考前端编译原理 这篇文章,本文不赘述。
    引入动态脚本的执行能力就像是一把双刃剑,它给配置策略的实现带来极大的灵活性,但同时,它的安全性、调试的便捷性也是面临的问题。基于这些考量,对下发的脚本做如下约束:

    • 限制作用域。代码执行环境的作用域限制在表单行实例内,内部无法访问小程序全局的对象和函数。
    • 逻辑与功能足够简单。代码中只处理表单的联动,这些联动方法都是封装在表单行实例上,对于开发者透明易用,在调试时更易发现问题。
    表单更新&数据维护

    表单模块与业务页面或其他组件交互的实质是表单模块在特定时间点的结构化数据的共享。表单模块内部通过属性设置、事件冒泡完成数据在内部的循环。


    数据通信模型

    上图中,可以比较形象地看出表单的更新及数据的获取方案

    • 表单更新。表单的调用方,设置顶层配置数据(数组类型),将小程序模板包裹的表单行动态渲染出来,每个表单行把相应的配置数据通过控件暴露的属性接口设置进去,通过多级联动完成表单视图的更新。
    • 状态获取control(控件)层是标准的基础控件或者经过开发者初步封装的控件,需要去实现抽象接口的getState方法, 用以从外部获取到控件的状态。form item(表单行)及其派生的子类,同样需要提供getState的接口,表单行在从基础控件获取到相应的状态后,根据自己的业务语义进行包装,可向自己的调用方抛出符合业务诉求的表单行数据。

    回顾整个方案的设计和实现,成功解决了本文开始提到的4个问题,并且具备以下优势

    • 基础组件与业务解耦,复用性强
    • 使用template包裹业务组件突破abstract component不能动态渲染组件的限制
    • 业务组件在同类型保险产品中有限可枚举、可复用
    • 基于小程序event loop的机制,稳定

    欢迎各位读者拍砖。

    相关文章

      网友评论

          本文标题:小程序表单动态配置与表单联动 - 实现篇

          本文链接:https://www.haomeiwen.com/subject/smblfctx.html