表单开发是 Web 开发中最常见的需求之一,表单本身的复杂度也在日益增加。我们如何借助技术手段,更好地实现表单结构、组织业务代码?本文介绍了使用 Vue.js 构造可配置化表单的一些经验。
背景
作为现代网页中最早具有逻辑的部分,表单至今仍在博客类、分类信息以及论坛等以用户发布的信息为核心的网站中,扮演着重要的角色。对这些网站来说,表单意味着信息的初始来源,因此它实际上承载了对于信息处理的第一手逻辑。对于不同的类目,表单的内容显然在业务上需要进行区分,所以,如何实现表单内容的区别化和可配置化就成为了这一类 Web 应用的一大重点。
传统的 Web 应用使用服务端直接输出表单的方式,来针对不同的页面逻辑输出不同的表单内容。一些相对完备的框架会提供服务端通过一些简单的配置输出表单的功能。例如,PHP 框架 Laravel 提供了通过 Form::textarea('content', null, ['class' => 'form-control'])
这样的方式来允许在视图的模板层渲染一个表单控件。然而,在交互逻辑日益复杂的今天,许多需求,例如:字段的实时校验、控件之间的联动,在这种模式下的实现是非常困难的,简单的服务端渲染已经远远不能满足业务的发展需求。
微软的 WPF 最早向我们展示了应用的 MVVM 模式,而 Knockout 则将它带入了前端的世界。到目前,以 React 和 Vue 为代表的视图层框架已经很好地将这种模式投入了生产中。而本文将要介绍的,则正是通过 Vue.js 框架来优化我们的表单开发能力和体验。
目标
抛开技术领域的探索,对于表单,我们要达成的目标是什么呢?
试想,有这样的一些需求:
- 一个最简单的表单中,需要有内容、地点、联系方式三个字段
- 内容字段至少需要填写8个字,且不能包含一些简单的违禁词组
- 地点字段是一个树形的选择控件,需要提供给用户从省级选到区县级的能力
- 联系方式是必填的,并且这个字段必须是手机号码
- 如果内容字段中出现了手机号码,且用户没有填写号码,需要将这个号码自动补充到联系方式中
大家看,即使是内容如此简单的表单,也会有这样的需求。有一些功能,例如:必填、格式校验,我们可以通过 HTML5 中的 required
或者 pattern
这样的字段来实现原生的约束,而更多复杂的功能则必须交由 JavaScript。抛开这一部分不谈,在纯页面结构上,我们想要的大概是这样:
<form class="form">
<div class="form-line">
<div class="form-control">
<textarea name="content"></textarea>
</div>
</div>
<div class="form-line">
<div class="form-control">
<input type="hidden" name="address">
<!-- 具体的控件实现 -->
</div>
</div>
<div class="form-line">
<div class="form-control">
<input type="text" name="contact">
</div>
</div>
<input type="hidden" name="_token" value="1wev5wreb8hi1mn=">
<button type="submit">提交</button>
</form>复制代码
而我们期望能有这样的配置直接配置上述的页面结构,以及其部分的逻辑:
[
{
"type": "textarea",
"name":