赞
踩
我的前端页面比较简单,多为表单类的小工具,所以研究了一下开源的表单设计组件。
例如:
form-create,他的官方示例,支持生成json和导入json。
考虑到集成到项目后,也可以使用官方demo进行解析json,因此采用form-create。
文档:https://www.form-create.com/v2/guide/
根据文档进行安装和引入
npm i @form-create/element-ui
在main.js里引入
import Vue from 'vue'
import formCreate from '@form-create/iview'
Vue.use(formCreate)
本次实践的低代码,写好一个框架,通过json配置实现表单的生成、提交等操作,期间涉及到的change、click事件也通过执行自定义脚本完成。
低代码时,最需要解决的是如何执行脚本,脚本格式是什么。
经过一些非开源平台的体验,查看他们请求的响应结果,小有思路后付诸实践,目前有两个方案,但pass了一个。
下面小小的记录一下吧。
第一种,也是被pass掉的一种:
第二种,利用事件注入:
在了解官方文档后,我的设计为:
事件名 | 说明 | 组件返回参数 | 自定义脚本入参 |
---|---|---|---|
submit | 表单提交事件 | formData, fapi | formData |
gs-change | change事件 | inject, val | formData,val,inject |
submit事件的json示例:
{ "formData": {}, "rule": [], "options": { "form": { "labelPosition": "left", "size": "mini", "labelWidth": "125px", "hideRequiredAsterisk": false, "showMessage": true, "inlineMessage": false }, "submitBtn": true, "resetBtn": false, "submitEvent": "(formData) => {\n // 在此编写代码 \n alert(JSON.stringify(formData)) \n}" } }
gs-change事件的json示例:
"emitPrefix": "gs",
"emit": [
{
"name": "change",
"inject": [
"(formData) => {\n // 在此编写代码}"
]
}
]
vue示例
<template> <div class="app-container"> <form-create v-model="egData.formData" :value.sync="egData.formData" :rule="egData.rule" :option="egData.options" @submit="onSubmit" @gs-change="onChange" @gs-blur="onBlur" /> </div> </template> <script> import axios from 'axios' export default { data() { return { egData: { // 表单默认值,也作为双向绑定的表单数据 formData: {}, rule: [], options: {} } } }, created() { this.getConfig() }, methods: { getConfig() { axios.get('/json/form-create/eg.json').then(res => { this.egData = res.data }) }, onSubmit(formData, fapi) { console.log(fapi) // eslint-disable-next-line no-eval const func = eval(fapi.options.submitEvent) func(formData) }, onChange(inject, val) { console.log(inject) // 具体脚本通过inject指定,格式为 "inject": ["(data, formData)=>{// 自定义}"] // eslint-disable-next-line no-eval const func = eval(inject.inject[0]) func(inject.$f.form, inject.self.value, inject) }, onBlur(inject) { console.log(inject) // eslint-disable-next-line no-eval const func = eval(inject.inject[0]) func(inject.$f.form, inject.self.value, inject) } } } </script> <style scoped> </style>
eg.json全部数据:
{ "formData": {}, "rule": [ { "type": "FcRow", "children": [ { "type": "col", "props": { "span": 24, "offset": 0, "push": 0, "pull": 0 }, "children": [ { "type": "input", "field": "f1", "title": "change事件", "info": "", "_fc_drag_tag": "input", "hidden": false, "display": true, "props": { "type": "text", "maxlength": 20, "minlength": 1, "showWordLimit": true, "clearable": true }, "$required": "测试必填项", "validate": [ { "trigger": "change", "mode": "required", "message": "", "required": true } ], "emitPrefix": "gs", "emit": [ { "name": "change", "inject": [ "(formData, data) => {\n // 在此编写代码\n alert('change已输入:' + data)\n}" ] } ] } ], "_fc_drag_tag": "col", "hidden": false, "display": true } ], "_fc_drag_tag": "row", "hidden": false, "display": true } ], "options": { "form": { "labelPosition": "left", "size": "mini", "labelWidth": "125px", "hideRequiredAsterisk": false, "showMessage": true, "inlineMessage": false }, "submitBtn": true, "resetBtn": false, "submitEvent": "(formData) => {\n // 在此编写代码 \n alert(JSON.stringify(formData)) \n}" } }
文档:https://designer.form-create.com/guide/
根据文档进行安装和引入
npm i @form-create/designer
在main.js里引入
import FcDesigner from '@form-create/designer'
Vue.use(FcDesigner)
<fc-designer ref="designer"/>
官方提供的API,常用到的有getRule、getOption、setRule、setOption,基本这四个就可以实现基础的表单;
当然,有更高级的需求,可以去查看文档。
// 拖拽好后生成json
this.$refs.designer.getRule()
this.$refs.designer.getOption()
// 根据json生成表单
this.$refs.designer.setRule()
this.$refs.designer.setOption()
本次主要想解决表单组件在线绑定事件,使用过一些可体验的低代码平台,最理想的体验方式是把绑定事件放在组件配置里,但是看完一圈API并没有发现可以修改。
后来便试了一下自定义按钮,插槽也并没有返回数据,无法做到组件和事件的一一对应了。
没事,坚信一定可以解决,便打印了this.$refs.designer,发现在选中组件后,输出结果里面有一个_self对象,包含了当前选中组件的rule。
这意味着,组件和事件可以一一对应上了,那后续的事件注入便没有难度了。
由于自定义了事件,组件内置的预览功能便无法满足了,自行开发一个预览。
<gen-func :active-rule="activeRule" @success="setEvent" /> setEvent(obj) { // 用户手动输入事件脚本后,回传到最终数据里 var rule = this.$refs.designer.getRule() var activeRule = this.$refs.designer._self.activeRule // 遍历找到当前选中的表单组件,赋值 var firstElement = rule[0] if (firstElement.type === 'FcRow') { var cols = firstElement.children cols.forEach(col => { var formItem = col.children if (formItem.field === activeRule.field) { formItem.emitPrefix = 'gs' formItem.emit = [] formItem.emit.push(obj) } }) } else { rule.forEach(formItem => { if (formItem.field === activeRule.field) { formItem.emitPrefix = 'gs' formItem.emit = [] formItem.emit.push(obj) } }) } this.$refs.designer.setRule(rule) this.msgSuccess('添加成功') }
genFunc.vue,代码编辑器用的vue-codemirror(ps:据说最新版仅支持vue3上,vue2可以下载4.x版本:
npm i vue-codemirror@4.x --save)
<template> <div class="app-container"> <el-form ref="form" class="form" :model="formData" label-position="left" label-width="68px"> <el-form-item label="事件"> <el-select v-model="formData.name" style="width: 100%"> <el-option v-for="item in eventList" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-form> <codemirror ref="myCodeMirror" v-model="code" :options="cmOptions" /> <div class="el-dialog__footer dialog-footer"> <el-button type="primary" @click="submitForm">确 定</el-button> </div> </div> </template> <script> import { codemirror } from 'vue-codemirror' // 组件样式 import 'codemirror/lib/codemirror.css' // 主题 import 'codemirror/theme/eclipse.css' // 语言模式 import 'codemirror/mode/javascript/javascript.js' import 'codemirror/mode/css/css.js' import 'codemirror/mode/xml/xml.js' // 代码展开折叠 import 'codemirror/addon/fold/foldcode.js' import 'codemirror/addon/fold/foldgutter.js' import 'codemirror/addon/fold/foldgutter.css' import 'codemirror/addon/fold/brace-fold.js' export default { components: { codemirror }, props: { activeRule: { type: Object, required: true } }, data() { return { eventList: [ { label: 'blur', value: 'blur' }, { label: 'change', value: 'change' }, { label: 'click', value: 'click' } ], cmOptions: { mode: 'text/javascript', // 实现javascript代码高亮 tabSize: 4, // tab的空格宽度 styleActiveLine: true, // 设置光标所在行高亮true/false lineNumbers: true, // 显示行号 theme: 'eclipse', // 设置主题cobalt/monokai json: true, readOnly: false, // 设置为只读true/false;也可设置为"nocursor"失去焦点 lineWrapping: false, foldGutter: true, gutters: [ 'CodeMirror-lint-markers', // 代码错误检测 'CodeMirror-linenumbers', 'CodeMirror-foldgutter' // 展开折叠 ] }, code: '(formData) => {\n // 在此编写代码\n}', formData: { name: 'change', inject: [] } } }, mounted() { var emit = this.activeRule.emit if (emit) { this.formData.name = emit[0].name this.code = emit[0].inject[0] } }, methods: { submitForm() { this.formData.inject[0] = this.code this.$emit('success', this.formData) } } } </script> <style scoped> </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。