手搓低代码表单(二)属性配置区
在前一节中,我们实现了表单渲染,但实际开发过程中,表单的属性需要支持修改,比如表单的label
,是否禁用disabled
,是否展示show-word-limit
等等, 对于属性的修改,只需要修改表单项对应schema
中定义属性的value值即可,然后实时响应到画布区。
属性配置区我们分为两块:
- 组件属性编辑区
组件属性编辑区用来配置组件的属性,比如label
,labelWidth
,showLabel
,changeTag
,tag
,tagIcon
,defaultValue
,required
,layout
,span
,document
,regList
等等。
- 表单属性编辑区
表单属性编辑区用来配置表单的属性,比如size
,labelPosition
,labelWidth
,labelSuffix
,hideRequiredAsterisk
,disabled
,gutter
,formBtns
,unFocusedComponentBorder
等等。
最终要实现的效果图如下:
组件属性编辑区
props数据的绑定
编辑区的组件属性编辑区,我们还是以el-input为例,以下是对el-input
的定义:
js
const elInput = {
__config__: {
label: '单行文本',
labelWidth: null,
showLabel: true,
changeTag: true,
tag: 'el-input',
tagIcon: 'input',
defaultValue: undefined,
required: true,
layout: 'colFormItem',
span: 24,
document: 'https://element.eleme.cn/#/zh-CN/component/input',
// 正则校验规则
regList: [{
pattern: '/^1(3|4|5|7|8|9)\d{9}$/',
message: '手机号格式错误'
}]
},
// 组件的插槽属性
__slot__: {
prepend: '',
append: ''
},
__vModel__: 'mobile',
placeholder: '请输入手机号',
style: { width: '100%' },
clearable: true,
'prefix-icon': 'el-icon-mobile',
'suffix-icon': '',
maxlength: 11,
'show-word-limit': true,
readonly: false,
disabled: false
}
这里以label
属性为例,在右侧编辑区,我们通过v-model绑定了activeData
(activeData
为当前选中组件)的label
属性,这样我们就可以实时的修改数据。其他的props
属性与之类似。
js
<el-form-item v-if="activeData.__config__.label!==undefined" label="标题">
<el-input v-model="activeData.__config__.label" placeholder="请输入标题" />
</el-form-item>
vModel绑定
vModel绑定如下,也是直接绑定到activeData
中定义的__vModel__
属性。
js
<el-form-item v-if="activeData.__vModel__ !== undefined" label="字段名">
<el-input v-model="activeData.__vModel__" placeholder="请输入字段名" />
</el-form-item>
举个例子:当我们创建一个用户名的表单项,我们可以给它绑定一个字段名,比如username
,当我们在画布区中的用户名表单项中输入xunwukong
时,那么xunwukong
其实是绑定到了defaultValue
上。
插槽属性绑定
插槽的绑定与props
属性类似,在el-input
中,我们定义了__slot__
属性,在绑定的时候,也是通过v-model绑定到activeData
中定义的__slot__
属性。
js
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.prepend!==undefined" label="前缀">
<el-input v-model="activeData.__slot__.prepend" placeholder="请输入前缀" />
</el-form-item>
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.append!==undefined" label="后缀">
<el-input v-model="activeData.__slot__.append" placeholder="请输入后缀" />
</el-form-item>
番外
这里我们仅仅对el-input
进行了配置,实际上对于不同的组件,配置也是不同的,我们可以根据需求进行扩展,比如el-select
组件,有和el-input
公用的属性,也有不同的属性,el-select
中有options
属性,options
在配置的时候,我们就需要支持添加选项,支持修改选项的先后顺序,支持删除选项,这些配置都是和el-select
相关的,这里我们也简单举个例子, 如下是el-select的定义:
js
const selectComponents = [
{
__config__: {
label: '下拉选择',
showLabel: true,
labelWidth: null,
tag: 'el-select',
tagIcon: 'select',
layout: 'colFormItem',
span: 24,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/select'
},
__slot__: {
options: [{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}]
},
placeholder: '请选择',
style: { width: '100%' },
clearable: true,
disabled: false,
filterable: false,
multiple: false
}
]
options
中配置了下拉选项,在渲染的时候通过遍历options
属性,渲染出下拉选项:
js
options(h, conf) {
const list = []
conf.__slot__.options.forEach(item => {
list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
})
return list
}
如上代码所示,options
属性是一个函数,函数接收两个参数,一个是h
,一个是conf
,h
是createElement的别名,conf
是当前选中的组件的配置信息。 在编辑区域中,我们通过v-model绑定到activeData
中定义的__slot__
属性上:
vue
<template v-if="['el-select'].includes(activeData.__config__.tag)">
<el-divider>选项</el-divider>
<draggable
:list="activeData.__slot__.options"
:animation="300"
group="selectItem"
handle=".option-drag"
>
<div v-for="(item, index) in activeData.__slot__.options" :key="index" class="select-item">
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input :value="item.value" size="small" @input="setOptionValue(item, $event)" placeholder="选项值" />
<div class="close-btn select-line-icon" @click="activeData.__slot__.options.splice(index, 1)">
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px;">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem">
添加选项
</el-button>
</div>
<el-divider />
</template>
在上述代码中,遍历options
属性,渲染出下拉选项。同时支持添加选项,删除选项等功能,同时通过draggable
组件支持拖拽排序。
表单校验配置
每个表单项可能有对应的校验规则,比如required
,pattern
等等,这些属性我们可以通过v-model绑定到activeData
中定义的regList
属性上。
vue
<template v-if="Array.isArray(activeData.__config__.regList)">
<el-divider>正则校验</el-divider>
<div
v-for="(item, index) in activeData.__config__.regList"
:key="index"
class="reg-item"
>
<span class="close-btn" @click="activeData.__config__.regList.splice(index, 1)">
<i class="el-icon-close" />
</span>
<el-form-item label="表达式">
<el-input v-model="item.pattern" placeholder="请输入正则" />
</el-form-item>
<el-form-item label="错误提示" style="margin-bottom:0">
<el-input v-model="item.message" placeholder="请输入错误提示" />
</el-form-item>
</div>
<div style="margin-left: 20px">
<el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
添加规则
</el-button>
</div>
</template>
如上所示,regList
为一个数组,数组中的每个元素都是一个对象,对象中包含pattern
和message
两个属性,pattern
为正则表达式,message
为错误提示。同时我们可以添加新的规则。
表单属性编辑区
表单的属性作用于el-form
组件,实现代码也比较简单:
vue
<el-form-item label="表单名">
<el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
</el-form-item>
<el-form-item label="表单模型">
<el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
</el-form-item>
<el-form-item label="校验模型">
<el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
</el-form-item>
<el-form-item label="表单尺寸">
<el-radio-group v-model="formConf.size">
<el-radio-button label="medium">
中等
</el-radio-button>
<el-radio-button label="small">
较小
</el-radio-button>
<el-radio-button label="mini">
迷你
</el-radio-button>
</el-radio-group>
</el-form-item>
上述代码中我们通过v-model
绑定了formConf中的属性,formRef
为el-form
组件的ref
属性,formModel
为el-form
组件的model
属性,formRules
为el-form
组件的rules
属性,size
为el-form
组件的size
属性,其他的属性也是类似配置。
表单项的属性配置和表单的配置是不同的,表单项的配置是针对每个组件的,表单的配置是针对整个表单的,最终都是绑定到schema
上来实现响应式的。
总结
今天我们把组件的属性编辑区实现完成,到目前为止,我们完成了物料区的开发,画布区的开发,属性编辑区的开发。还有一些功能点没有讲到,比如:画布区的表单项的拖拽,画布区的表单项的删除,画布区的表单项的复制,这些功能点比较简单,都是对画布区数据的增删改,就不细讲了。 我们在后续的文章中,会继续讲到出码的功能。
如果你喜欢我的内容,请点赞评论告诉我,我会努力做得更好!