一、基本结构渲染
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-formref="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-itemv-if="!item.children || !item.children!.length":prop="item.prop":label="item.label"><componentv-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-itemv-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!]"><componentv-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.valuer[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()})// 监听父组件传递进来的optionswatch(() => props.options, () => {initForm()}, { deep: true })</script><style lang='scss' scoped></style>
