引言
最近发现各大厂/小厂 都在搞自己的表单生成器/低代码平台,以提高开发的工作效率,此文将带着大家写一个初版的vue表单生成器。
demo链接 sutianbinde.github.io/vue-form-re…
github源码 github.com/sutianbinde…
建议快速阅读5-10分钟,跟随开发时间3~5小时
---
实现
1、使用vue-cli生成项目 (对于非本文技术点的步骤,下面就简写了)
我们示例工程用的 vue2.x版本
2、安装element 、 sass-loader、sass,并启动项目
此demo以element为基础渲染组件,后续再升级支持别的库。
3、借助element ui实现基础布局
这里主要组件 分为左中右 三个组件,我们后续代码也在这三个组件中实现。
基本目录结构如下:
4、在Left.vue中,定义基本的表单组件,并渲染成如上图所示的按钮显示
json格式
componentList: [
{
label: "输入框",
component: "ElInput"
},
{
label: "选择器",
component: "ElSelect"
},
{
label: "单选框",
component: "ElRadio"
},
{
label: "多选框",
component: "ElCheckbox"
},
{
label: "日期选择器",
component: "ElDatePicker"
}
]
5、当点击或拖拽结束的时候,向middle.vue组件传递组件名称,并生成组件schema数据。
组件schema数据示例如下,
componentData: [
{
component: "ElSelect", // 组件名称
label: "表单label",
$id: "ElSelect_" + Math.floor(Math.random() * 1000), // 未来获取表单v-model数据的key
propValue: { //需要绑定到表单组件上的props
value: "", // demo中绑定v-model的key。
enums: ["a", "b", "c"], // 选项的值
enumNames: ["早", "中", "晚"] // 选项的名称
}
},
{
component: "ElRadio",
label: "表单label",
$id: "ElRadio_" + Math.floor(Math.random() * 1000),
propValue: {
value: "",
enums: ["a", "b", "c"],
enumNames: ["早", "中", "晚"]
}
}
],
拿到上面数据,我们如何渲染成表单组件呢,这里使用vue 的 component组件进行渲染,即可渲染出对应的组件
<component
:is="item.component"
v-bind="item.propValue"
v-model="item.propValue.value" />
但是,element的一些表单组件是多标签使用的,单标签并不能渲染出完整组件,这时候,就需要我们重写这些组件,比如ElSelect组件,这样在渲染的时候就会渲染成我们重写的组件。
重写策略为:1、继承并传递所有props,2、响应所有事件,3、按照schema数据中的 enums 和 enumNames 生成选项
我们新建一个文件夹 widgets 用来编写需要重新的组件。示例项目中,我们只重写了两个组件。
Select.vue的重写代码示例
<script>
import { Select } from "element-ui";
export default {
props: {
enums: {
type: Array,
default: () => []
},
enumNames: {
type: Array,
default: () => []
},
...Select.props
},
render() {
return (
<el-select {...{ props: this.$props, on: this.$listeners }}>
{this.enums.map((val, index) => {
return <el-option value={val} label={this.enumNames[index]} />;
})}
</el-select>
);
}};
</script><style></style>
然后我们需要在middle.vue中引入并注册这个组件,这样meddle.vue中遇到'ElSelect'组件的时候,就会渲染成重写后的组件了。
...
import ElSelect from "../widgets/select.vue";
import ElRadio from "../widgets/radio.vue";
export default {
components: {
ElSelect,
ElRadio
},
...
组件渲染之后,效果如下(组件外的基本布局部分,这里就不列举了)
6、点击表单的时候,实现选中,删除,复制,移动等功能
选中:这里我们监听表单item的native点击事件(因为点击整个form-item都要选中,所以不能只监听 表单的点击事件)
<el-form-item
:label="item.label"
@click.native="selectCurComponent($event, item)">
<component
:is="item.component"
v-bind="item.propValue"
v-model="item.propValue.value"
/>
</el-form-item>
删除,复制,移动 只需按照schema格式操作componentData数组即可。
7、根据选中项 实现右侧right.vue中的属性编辑
通过选中的item对应的component属性,可以获取到element的原始组件,找到该组件,就可以获取所有的props。
import ElementUI from "element-ui";
// ElementUI中组件key 不包含'El',比如 ElSelect 在 ElementUI对象中的key为 'Select',所以这里截掉了前两位// 如果要适应不同组件库,组件前缀应该是在渲染的时候再加,本文章为了方便,所有都默认加上了El
ElementUI[this.activeItem.component.slice(2).props;
8、处理Select/Radio选项的删除和新增
我们生成shema的时候默认给选项给了初始值 enums 和 选项的名称 enumNames,
在right.vue中,我们根据这两个数组,生成两个可以新增选项的下拉框,这样,就可以手动输入选项了,最后以选中项作为结果再设置到middle.vue中此表单数据的schema数据中。
基本代码示例
// right.vue中设置数据的时候,将 传递过来的nums赋值给对应的key,this.enumOptions = defaultProps.enums;this.enumValue = defaultProps.enums;this.enumNameOptions = defaultProps.enumNames;this.enumNameValue = defaultProps.enumNames;
// right.vue 中根据这几个值渲染出两个特殊表单
<div>选项字段:</div><el-select v-model="enumValue" multiple filterable allow-create default-first-option placeholder="请选择" @change="valueChange('enums', $event)"> <el-option v-for="item in enumOptions" :key="item" :label="item" :value="item" ></el-option></el-select><div>选项名称:</div><el-select v-model="enumNameValue" multiple filterable allow-create default-first-option placeholder="请选择" @change="valueChange('enumNames', $event)"> <el-option v-for="item in enumNameOptions" :key="item" :label="item" :value="item" ></el-option></el-select>
// right.vue 数据变化的时候触发改变事件
valueChange(key, value) { this.$emit("change", key, value);}
// app.vue中接收到change事件,并调用middle.vue中的方法
// 在middle.vue中更改对应的值
changeProps(key, value) { this.$set(this.activeItem.propValue, key, value);}
9、right.vue普通props我们这里简单处理成input 和 checkbox,渲染之后,监听input 和change事件,然后去改变middle.vue中对应组件schema数据中的propValue即可。
基本流程同 8
10、schema的查看和复制。
生成用于生产环境的schema应该包括两个部分,一部分为表单数据,另一部分用于绑定v-model,数据示例如下
{
"schema": [
{
"component": "ElSelect",
"label": "表单label",
"$id": "ElSelect_944",
"propValue": {
"enums": [
"a",
"b",
"c"
],
"enumNames": [
"早",
"中",
"晚"
]
}
},
{
"component": "ElRadio",
"label": "表单label",
"$id": "ElRadio_609",
"propValue": {
"enums": [
"a",
"b",
"c"
],
"enumNames": [
"早",
"中",
"晚"
]
}
}
],
"model": {
"ElSelect_944": "",
"ElRadio_609": ""
}
}
demo示例中是将schema数据直接放到pre标签中展示,利用document.execCommand("copy")进行复制。
逻辑比较交单,可去仓库代码中查看。
11、schema生成之后,如何使用。
我们需要编写一个通用的render组件,在实际项目中,只要传入schema数据,即可生成对应表单,期待使用方式如下
<render-components
:componentData="schema" // 表单渲染数据
:model="model" // 表单绑定的值></render-components>
12、根据这种使用方式编写render-components组件。基本逻辑就是使用components组件将表单schema遍历渲染出表单,内部注册覆盖的组件,绑定对应的v-model。
<template>
<el-form
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
:model="model"
>
<el-form-item
v-for="(item, index) in componentData"
:key="index"
:label="item.label"
>
<component
:is="item.component"
v-bind="item.propValue"
v-model="model[item.$id]"
/>
</el-form-item>
</el-form>
</template>
<script>
import ElSelect from "../widgets/select.vue";
import ElRadio from "../widgets/radio.vue";
export default {
components: {
ElSelect,
ElRadio
},
props: {
componentData: {
type: Array,
default: () => []
},
model: {
type: Object,
default: () => ({})
}
}};
</script>
<style lang="scss" scoped>.demo-ruleForm { flex: 1;}</style>
后续计划...
上面只是实现了一个demo版本的表单生成器,如果要正在用于实际生产环境,需要重新规划组织结构、验证schema格式、分组件库实现不同的渲染逻辑、实现表单内部联动逻辑及验证机制、另外还需要提供第三方注册api等。可能会另起一个工程实现pro版。
文章标题XXX | 创作者训练营 征文活动正在进行中......
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!