来自产品MM的需要
- 首先看一个简略的表单需要,上面是一个简略数据收集表的一部分,抉择“立刻失效”后呈现
"失效日期"且必填。
用Vue + Element UI很容易实现这个需要,开动VSCode一顿惯例操作,10分钟出工。
- 第二天产品MM又找过去了,需要有一丢丢改变,如下图示:
流动类型为冲单或回馈时,反对失效条件;条件反对流动人数、流动天数(二者为且的关系)
肿么办?启动VSCode,又是一通惯例操作,这次改变麻烦一点,一个小时出工,当然要公布上线的话,还免不了推送、构建、测试、打包、重新部署。
- 然鹅,游戏并没有over,过两天产品MM又来找你了,因为需要疏漏了一个中央:失效条件须要加上“峰值”判断,如下图所示:
如此周而复始,需要永远在不停迭代,前端开发疲于奔命,终于有一天你变成了这般模样:
解决之道
针对上述这种十分多变的表单需要,简略剖析一下,变动的次要是表单控件和逻辑判断,所以首先想到的就是开发一个配置式的表单,设计一个全新的表单schema标准,而后依据schema编写表单JSON对象,最初由表单JSON动静生成表单。上面就是一段常见的基于schema的表单JSON代码:
{ title: '流动类型', key: 'act_type', type: 'radio', props: { options: { 1: '拉新', 2: '冲单', 3: '回馈' } }},
这种思路曾经十分成熟了,有十分多成熟的开源表单我的项目采纳了这种思路,但这个计划有两个比拟显著的毛病:
1. 使用者须要学习表单schema标准;
2. 难于实现简单的表单交互逻辑。
为了解决第一个schema标准学习老本的问题,能够基于表单schema开发一个拖拽式的所见即所得的在线表单设计器,这个也有十分多的开源我的项目实现了,各种form generator、form creator等等,鄙人不才也搞了一个VForm,有趣味的童鞋能够尝尝鲜:
VForm,一个Vue动静表单设计器,==>>点此体验
为了解决第二个问题,如何实现动静表单的简单交互逻辑,也是本文的次要指标,本文的解决思路是——为动静表单减少可编程接口,即通过组件的交互事件和API办法实现交互逻辑,JS代码才是王道。
实现表单的可编程接口
从第一局部的表单需要来剖析,要实现表单交互逻辑,第一步是裸露组件的交互事件,比方“流动类型”组件点击扭转后触发的onChange事件;第二步就是在事件中对组件进行准确操控,比方显示或暗藏某些组件、设置组件必填属性、设置组件禁用状态、增加或移除组件CSS款式等等。
第一步非常简单,只有给表单schema减少组件的自定义事件属性即可,上面schema给input组件减少了7个自定义事件:
{ type: 'input', icon: 'text-field', formItemFlag: true, options: { name: '', //组件根本属性 label: '', labelAlign: '', type: 'text', defaultValue: '', placeholder: '', //------------------- onCreated: '', //自定义事件 onMounted: '', onInput: '', onChange: '', onFocus: '', onBlur: '', onValidate: '', }, },
接下来须要退出一个反对语法高亮、代码提醒的代码编辑器组件,这里抉择成熟、久经考验的AceEditor,GitHub有一个打包好的ace-builds,装置应用非常简略:
装置ace:npm i ace-builds
而后基于ace封装一个简略的JS代码编辑器,截取局部代码如下所示:
<template> <div class="ace-container"> <!-- 官网文档中应用id,这里禁止应用,在前期打包后容易呈现问题,应用 ref 或者 DOM 就行 --> <div class="ace-editor" ref="ace"></div> </div></template><script> import ace from 'ace-builds' /* 启用此行后webpack打包回生成很多动静加载的js文件,不便于部署,故禁用!! 特地提醒:禁用此行后,须要调用ace.config.set('basePath', 'path...')指定动静js加载URL!! */ //import 'ace-builds/webpack-resolver' import 'ace-builds/src-min-noconflict/theme-sqlserver' // 新设主题 import 'ace-builds/src-min-noconflict/mode-javascript' // 默认设置的语言模式 import 'ace-builds/src-min-noconflict/mode-json' // import 'ace-builds/src-min-noconflict/mode-css' // import 'ace-builds/src-min-noconflict/ext-language_tools' import {ACE_BASE_PATH} from "@/utils/config"; export default { name: 'CodeEditor', props: { value: { type: String, required: true }, readonly: { type: Boolean, default: false }, mode: { type: String, default: 'javascript' }, userWorker: { //是否开启语法查看,默认开启 type: Boolean, default: true }, }, mounted() { ace.config.set('basePath', ACE_BASE_PATH) }, //省略methods办法... }
给CodeEditor减少代码提醒:
addAutoCompletion(ace) { let acData = [ {meta: 'VForm API', caption: 'getWidgetRef', value: 'getWidgetRef()', score: 1}, {meta: 'VForm API', caption: 'getFormRef', value: 'getFormRef()', score: 1}, //TODO: 待补充!! ] let langTools = ace.require('ace/ext/language_tools') langTools.addCompleter({ getCompletions: function(editor, session, pos, prefix, callback) { if (prefix.length === 0) { return callback(null, []); }else { return callback(null, acData); } } }) }
封装后的CodeEditor成果如下(此处应用VForm演示):
交互事件有了,接下来实现组件的操控API办法,这里又分两步走:
1. 获取到组件ref;
2. 调用组件的methods属性中的办法;
首先给表单减少一个refList的provider属性,在组件中inject注入,当每个组件创立时将本组件实例注入refList对象:
//...此处省略 inject: ['refList'], //...此处省略 created() { this.registerToRefList() }, methods: { registerToRefList() { this.refList[this.field.options.name] = this }, //...此处省略 }
接下来,再封装一个简略的getWidgetRef办法,该办法通过组件名称获取到组件实例:
getWidgetRef(widgetName, showError) { let foundRef = this.refList[widgetName] if (!foundRef && !!showError) { this.$message.error('Ref not found') } return foundRef },
通过组件实例即可调用methods属性中的组件办法,组件办法能够任意裁减。
实现一个简略的点击事件交互:
/* 下述代码在“喜爱喝酒还是饮料?”单选按钮onChange事件中执行 */var alcoholChkWidget = this.getWidgetRef('alcoholChk')var drinkChkWidget = this.getWidgetRef('drinkChk')if (value === 1) { alcoholChkWidget.setHidden(false) //setHidden是自定义的API办法,管制组件显示或暗藏 drinkChkWidget.setHidden(true)} else { alcoholChkWidget.setHidden(true) drinkChkWidget.setHidden(false)}
交互成果如下:
须要揭示的是,交互事件中的js代码是在表单运行期间执行,代码不会被Babel编译,具体执行过程是:通过Function生成一个匿名函数,传入指定参数后执行,没有应用低效且不平安的eval办法。
如果要调试交互JS代码也非常简单,只须要在代码中须要下断点的地位退出"debugger",代码执行到此处会进入调试状态(Chrome内核的浏览器都反对)。
论断
综上所述,实现一个可编程的Vue动静表单,大体实现思路如下:
1.设计一个表单schema标准,基于该schema标准开发一个拖拽式的表单设计器;
2.裸露组件的交互事件,并按需要实现组件的API办法;
3.提供一个语法高亮、有代码提醒性能的JS代码编辑器;
4.通过在交互事件中调用组件API办法,即可实现表单简单交互逻辑;
5.完满实现预约指标。
鄙人的新轮子VForm齐全实现了上述性能,有趣味的小伙伴能够体验尝试。
点此立刻体验
具体应用文档:VForm专栏