表单组件代码
import { h, computed, ref } from 'vue'
import type { PropType } from 'vue'
import { Form, Input, Radio, FormItem, Checkbox } from '@arco-design/web-vue'
type RestrictKey<T, K extends keyof any> = {
[P in keyof T]: P extends K ? never : T[P];
};
export type FormPropsType =RestrictKey<{
model?: string;
items: {
[key: string]: {
type: 'radio' | 'input' | 'checkbox' | 'slot'
config: RestrictKey<{
[key: string]: any;
field?: string;
},'field'>
slotFormConfig: {
modelValue: any
[key: string]: any
}
}
}
[key: string]: any
},'model'>
export default {
components: {
Form,
Input,
Radio,
FormItem,
Checkbox
},
props: {
config: {
type: Object as PropType<FormPropsType>
}
},
setup(props: FormPropsType, { expose, emit, slots }: any) {
const FormRef = ref()
const formItemComponent = computed(() => {
return Array.from(Object.keys(props.config.items)).map(formItemName => {
const formItemConfig = props.config.items[formItemName]
formItemConfig.slotFormConfig['onUpdate:modelValue'] = (e:any) => {
formItemConfig.slotFormConfig.modelValue = e
}
formItemConfig.config['field'] = formItemName
let slotComp
switch (formItemConfig.type) {
case 'slot':
slotComp = h(
'div',
{
style:{
width:'100%',
height:'100%'
}
},
slots[formItemName](props.config.items[formItemName].slotFormConfig)
)
break
case 'input':
slotComp = h(Input, props.config.items[formItemName].slotFormConfig)
break
case 'radio':
slotComp = h(Radio, props.config.items[formItemName].slotFormConfig)
break
case 'checkbox':
slotComp = h(Checkbox, props.config.items[formItemName].slotFormConfig)
break
}
const comp = h(FormItem, formItemConfig.config, slotComp)
return comp
})
})
const formComponent = computed(() => {
return h(
Form,
{
...props.config,
model: Object.keys(props.config.items)
.map(formItemName => {
return [
formItemName,
props.config.items[formItemName].slotFormConfig.modelValue
]
})
.reduce((acc: any, [key, value]) => {
acc[key] = value
return acc
}, {}),
ref: FormRef
},
formItemComponent.value
)
})
expose({
FormRef
})
return () => h('div', {}, formComponent.value)
}
}
示例代码
<script setup lang="ts">
import { ref } from 'vue'
import XForm from '@/components/common/x-form/index.ts'
import type { FormPropsType } from '@/components/common/x-form/index.ts'
import { defineEmits } from 'vue'
let emit = defineEmits(['update:selectedKeys'])
const xFormRef=ref()
const formConfig = ref<FormPropsType>({
items: {
name: {
type: 'slot',
config: {
label: '姓名',
rules: [{ required: true, message: 'Name is required' }],
style:{
width:'300px'
}
},
slotFormConfig: {
modelValue: ''
}
}
}
})
function verifyForm() {
xFormRef.value.FormRef.validate()
}
</script>
<template>
<XForm :config="formConfig" ref="xFormRef">
<template #name="scoped">
<a-input v-model="scoped.modelValue" />
</template>
</XForm>
<a-button type="primary" @click="verifyForm">校验</a-button>
</template>
<style scoped></style>