一、基本结构渲染
1.el-form在最外层
(1)el-form需要绑定model属性
遍历options,给model添加每个表单项prop属性,值为表单项的value
(2)给el-form绑定rules属性
遍历表单项,给rules添加prop属性,值为表单项的rules
2.循环遍历options创建el-form-item标签
单独绑定form-item常用属性(prop,label,rules),通过v-bind一并绑定组件特有属性
3.使用component动态组件渲染element-plus组件,并绑定属性
(1)利用is属性,动态渲染element组件
(2)绑定必传value
二、数据绑定
1.给el-form组件绑定model和rules属性
2.给component绑定model属性
三、渲染有子元素的组件
1.添加children属性
2.form组建中,进行条件渲染
(1)根据children属性,进行条件渲染
(2)有children时,component中间通过默认插槽放入子组件
四、监听prop.options
监听prop.options,更新渲染表单,为动态删减表单做准备
五、利用插槽加上表单操作项
1.form组件中加入一个具名插槽,用于渲染操作项
2.给插槽定义prop,为父组件提供表单实例、表单数据
3.difenExpose
想外界暴露属性,父组件可通过ref方式获取到子组件实例,调用该方法
<template>
<el-form
ref="form"
v-if="model"
:validate-on-rule-change="false"
:model="model"
:rules="rules"
v-bind="$attrs"
>
<template v-for="(item, index) in options" :key="index">
<el-form-item
v-if="!item.children || !item.children!.length"
:prop="item.prop"
:label="item.label"
>
<component
v-if="item.type !== 'upload' && item.type !== 'editor'"
:placeholder="item.placeholder"
v-bind="item.attrs"
:is="`el-${item.type}`"
v-model="model[item.prop!]"
></component>
<div id="editor" v-if="item.type === 'editor'"></div>
</el-form-item>
<el-form-item
v-if="item.children && item.children.length"
:prop="item.prop"
:label="item.label"
>
<component
:placeholder="item.placeholder"
v-bind="item.attrs"
:is="`el-${item.type}`"
v-model="model[item.prop!]"
>
<component
v-for="(child, i) in item.children"
:key="i"
:is="`el-${child.type}`"
:label="child.label"
:value="child.value"
></component>
</component>
</el-form-item>
</template>
<el-form-item>
<slot name="action" :form="form" :model="model"></slot>
</el-form-item>
</el-form>
</template>
<script lang='ts' setup>
import { PropType, ref, onMounted, watch, nextTick } from 'vue'
import { FormInstance, FormOptions } from './types/types'
import cloneDeep from 'lodash/cloneDeep'
import E from "wangeditor"
let props = defineProps({
// 表单的配置项
options: {
type: Array as PropType<FormOptions[]>,
required: true
},
// 用户自定义上传方法
httpRequest: {
type: Function
}
})
let model = ref<any>(null)
let rules = ref<any>(null)
let form = ref<FormInstance | null>()
let edit = ref()
// 初始化表单
let initForm = () => {
if (props.options && props.options.length) {
let m: any = {}
let r: any = {}
props.options.map((item: FormOptions) => {
m[item.prop!] = item.value
r[item.prop!] = item.rules
})
model.value = cloneDeep(m)
rules.value = cloneDeep(r)
}
}
// 重置表单
let resetFields = () => {
// 重置element-plus的表单
form.value!.resetFields()
// 重置富文本编辑器的内容
// 获取到富文本的配置项
if (props.options && props.options.length) {
let editorItem = props.options.find(item => item.type === 'editor')!
edit.value.txt.html(editorItem.value)
}
}
// 表单验证方法
let validate = () => {
return form.value!.validate
}
// 获取表单数据
let getFormData = () => {
return model.value
}
// 分发方法
defineExpose({
resetFields,
validate,
getFormData
})
onMounted(() => {
initForm()
})
// 监听父组件传递进来的options
watch(() => props.options, () => {
initForm()
}, { deep: true })
</script>
<style lang='scss' scoped>
</style>