feat: Form useForm 完成

This commit is contained in:
kailong321200875 2023-06-21 11:28:03 +08:00
parent 097b32e1a9
commit 3e4e27c21f
9 changed files with 173 additions and 26 deletions

View File

@ -115,7 +115,7 @@ defineExpose({
</script> </script>
<template> <template>
<div class="border-1 border-solid border-[var(--tags-view-border-color)] z-99"> <div class="border-1 border-solid border-[var(--tags-view-border-color)] z-10">
<!-- 工具栏 --> <!-- 工具栏 -->
<Toolbar <Toolbar
:editor="editorRef" :editor="editorRef"

View File

@ -41,6 +41,8 @@ export interface FormExpose {
setSchema: (schemaProps: FormSetProps[]) => void setSchema: (schemaProps: FormSetProps[]) => void
formModel: Recordable formModel: Recordable
getElFormRef: () => ComponentRef<typeof ElForm> getElFormRef: () => ComponentRef<typeof ElForm>
getComponentExpose: (field: string) => any
getFormItemExpose: (field: string) => any
} }
export { Form } export { Form }

View File

@ -73,6 +73,12 @@ export default defineComponent({
return propsObj return propsObj
}) })
//
const formComponents = ref({})
// form-item
const formItemComponents = ref({})
// //
const formModel = ref<Recordable>({}) const formModel = ref<Recordable>({})
@ -125,7 +131,37 @@ export default defineComponent({
const getOptions = async (fn: Function, field: string) => { const getOptions = async (fn: Function, field: string) => {
const options = await fn() const options = await fn()
console.log(field, options) setSchema([
{
field,
path: 'componentProps.options',
value: options
}
])
}
/**
* @description: 获取表单组件实例
* @param filed 表单字段
*/
const getComponentExpose = (filed: string) => {
return unref(formComponents)[filed]
}
/**
* @description: 获取formItem实例
* @param filed 表单字段
*/
const getFormItemExpose = (filed: string) => {
return unref(formItemComponents)[filed]
}
const setComponentRefMap = (ref: any, filed: string) => {
formComponents.value[filed] = ref
}
const setFormItemRefMap = (ref: any, filed: string) => {
formItemComponents.value[filed] = ref
} }
expose({ expose({
@ -135,14 +171,15 @@ export default defineComponent({
delSchema, delSchema,
addSchema, addSchema,
setSchema, setSchema,
getElFormRef getElFormRef,
getComponentExpose,
getFormItemExpose
}) })
// formModel // formModel
watch( watch(
() => unref(getProps).schema, () => unref(getProps).schema,
(schema = []) => { (schema = []) => {
console.log('@@####')
formModel.value = initModel(schema, unref(formModel)) formModel.value = initModel(schema, unref(formModel))
}, },
{ {
@ -193,8 +230,8 @@ export default defineComponent({
} }
const formItemSlots: Recordable = { const formItemSlots: Recordable = {
default: () => { default: () => {
if (slots[item.field]) { if (item?.formItemProps?.slots?.default) {
return getSlot(slots, item.field, formModel.value) return item?.formItemProps?.slots?.default(formModel.value)
} else { } else {
const Com = componentMap[item.component as string] as ReturnType<typeof defineComponent> const Com = componentMap[item.component as string] as ReturnType<typeof defineComponent>
@ -254,6 +291,7 @@ export default defineComponent({
return ( return (
<Com <Com
vModel={formModel.value[item.field]} vModel={formModel.value[item.field]}
ref={(el: any) => setComponentRefMap(el, item.field)}
{...(autoSetPlaceholder && setTextPlaceholder(item))} {...(autoSetPlaceholder && setTextPlaceholder(item))}
{...setComponentProps(item)} {...setComponentProps(item)}
style={item.componentProps?.style || {}} style={item.componentProps?.style || {}}
@ -278,7 +316,12 @@ export default defineComponent({
} }
} }
return ( return (
<ElFormItem {...(item.formItemProps || {})} prop={item.field} label={item.label || ''}> <ElFormItem
ref={(el: any) => setFormItemRefMap(el, item.field)}
{...(item.formItemProps || {})}
prop={item.field}
label={item.label || ''}
>
{formItemSlots} {formItemSlots}
</ElFormItem> </ElFormItem>
) )

View File

@ -756,6 +756,7 @@ export interface FormSetProps {
} }
export interface FormItemProps { export interface FormItemProps {
ref?: any
labelWidth?: string | number labelWidth?: string | number
required?: boolean required?: boolean
rules?: FormItemRule | FormItemRule[] rules?: FormItemRule | FormItemRule[]

View File

@ -1,5 +1,5 @@
import type { Form, FormExpose } from '@/components/Form' import type { Form, FormExpose } from '@/components/Form'
import type { ElForm } from 'element-plus' import type { ElForm, ElFormItem } from 'element-plus'
import { ref, unref, nextTick } from 'vue' import { ref, unref, nextTick } from 'vue'
import { FormSchema, FormSetProps, FormProps } from '@/components/Form' import { FormSchema, FormSetProps, FormProps } from '@/components/Form'
@ -74,12 +74,26 @@ export const useForm = () => {
getFormData: async <T = Recordable>(): Promise<T> => { getFormData: async <T = Recordable>(): Promise<T> => {
const form = await getForm() const form = await getForm()
return form?.formModel as T return form?.formModel as T
},
getComponentExpose: async (field: string) => {
const form = await getForm()
return form?.getComponentExpose(field)
},
getFormItemExpose: async (field: string) => {
const form = await getForm()
return form?.getFormItemExpose(field) as ComponentRef<typeof ElFormItem>
},
getElFormExpose: async () => {
await getForm()
return unref(elFormRef)
} }
} }
return { return {
register, register,
formRef: elFormRef,
methods methods
} }
} }

View File

@ -285,7 +285,9 @@ export default {
richText: 'Rich text', richText: 'Rich text',
form: 'Form', form: 'Form',
// 远程加载 // 远程加载
remoteLoading: 'Remote loading' remoteLoading: 'Remote loading',
// 聚焦
focus: 'Focus'
}, },
guideDemo: { guideDemo: {
guide: 'Guide', guide: 'Guide',

View File

@ -284,7 +284,9 @@ export default {
richText: '富文本编辑器', richText: '富文本编辑器',
form: '表单', form: '表单',
// 远程加载 // 远程加载
remoteLoading: '远程加载' remoteLoading: '远程加载',
// 聚焦
focus: '聚焦'
}, },
guideDemo: { guideDemo: {
guide: '引导页', guide: '引导页',

View File

@ -14,7 +14,8 @@ import {
ElRadio, ElRadio,
ElRadioButton, ElRadioButton,
ElCheckbox, ElCheckbox,
ElCheckboxButton ElCheckboxButton,
ElInput
} from 'element-plus' } from 'element-plus'
import { getDictOneApi } from '@/api/common' import { getDictOneApi } from '@/api/common'
@ -1384,6 +1385,18 @@ const schema = reactive<FormSchema[]>([
} }
} }
}, },
{
field: 'field69-1',
component: 'Input',
label: `custom formItem`,
formItemProps: {
slots: {
default: (formModel: any) => {
return <ElInput v-model={formModel['field69-1']} />
}
}
}
},
{ {
field: 'field70', field: 'field70',
component: 'Divider', component: 'Divider',
@ -1401,6 +1414,45 @@ const schema = reactive<FormSchema[]>([
const res = await getDictOneApi() const res = await getDictOneApi()
return res.data return res.data
} }
},
{
field: 'field72',
label: `${t('formDemo.selectV2')}`,
component: 'SelectV2',
componentProps: {
options: []
},
// option
optionApi: async () => {
const res = await getDictOneApi()
return res.data
}
},
{
field: 'field73',
label: `${t('formDemo.checkboxGroup')}`,
component: 'CheckboxGroup',
componentProps: {
options: []
},
// option
optionApi: async () => {
const res = await getDictOneApi()
return res.data
}
},
{
field: 'field74',
label: `${t('formDemo.radioGroup')}`,
component: 'RadioGroup',
componentProps: {
options: []
},
// option
optionApi: async () => {
const res = await getDictOneApi()
return res.data
}
} }
]) ])

View File

@ -4,7 +4,7 @@ import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useForm } from '@/hooks/web/useForm' import { useForm } from '@/hooks/web/useForm'
import { reactive, unref, ref } from 'vue' import { reactive, unref, ref } from 'vue'
import { ElButton } from 'element-plus' import { ElButton, ElInput } from 'element-plus'
import { useValidator } from '@/hooks/web/useValidator' import { useValidator } from '@/hooks/web/useValidator'
import { getDictOneApi } from '@/api/common' import { getDictOneApi } from '@/api/common'
@ -36,6 +36,9 @@ const schema = reactive<FormSchema[]>([
value: '2' value: '2'
} }
] ]
},
formItemProps: {
rules: [required()]
} }
}, },
{ {
@ -92,31 +95,37 @@ const schema = reactive<FormSchema[]>([
} }
]) ])
const { register, methods, elFormRef } = useForm() const { register, methods } = useForm()
const {
setProps,
delSchema,
addSchema,
setValues,
setSchema,
getComponentExpose,
getFormItemExpose,
getElFormExpose
} = methods
const changeLabelWidth = (width: number | string) => { const changeLabelWidth = (width: number | string) => {
const { setProps } = methods
setProps({ setProps({
labelWidth: width labelWidth: width
}) })
} }
const changeSize = (size: string) => { const changeSize = (size: string) => {
const { setProps } = methods
setProps({ setProps({
size size
}) })
} }
const changeDisabled = (bool: boolean) => { const changeDisabled = (bool: boolean) => {
const { setProps } = methods
setProps({ setProps({
disabled: bool disabled: bool
}) })
} }
const changeSchema = (del: boolean) => { const changeSchema = (del: boolean) => {
const { delSchema, addSchema } = methods
if (del) { if (del) {
delSchema('field2') delSchema('field2')
} else if (!del && schema[1].field !== 'field2') { } else if (!del && schema[1].field !== 'field2') {
@ -143,10 +152,10 @@ const changeSchema = (del: boolean) => {
} }
} }
const setValue = (reset: boolean) => { const setValue = async (reset: boolean) => {
const { setValues } = methods const elFormExpose = await getElFormExpose()
if (reset) { if (reset) {
unref(elFormRef)?.resetFields() elFormExpose?.resetFields()
} else { } else {
setValues({ setValues({
field1: 'field1', field1: 'field1',
@ -162,7 +171,6 @@ const setValue = (reset: boolean) => {
const index = ref(7) const index = ref(7)
const setLabel = () => { const setLabel = () => {
const { setSchema } = methods
setSchema([ setSchema([
{ {
field: 'field2', field: 'field2',
@ -212,14 +220,16 @@ const addItem = () => {
index.value++ index.value++
} }
const formValidation = () => { const formValidation = async () => {
unref(elFormRef)!.validate((isValid) => { const elFormExpose = await getElFormExpose()
elFormExpose?.validate((isValid) => {
console.log(isValid) console.log(isValid)
}) })
} }
const verifyReset = () => { const verifyReset = async () => {
unref(elFormRef)?.resetFields() const elFormExpose = await getElFormExpose()
elFormExpose?.resetFields()
} }
const getDictOne = async () => { const getDictOne = async () => {
@ -235,6 +245,20 @@ const getDictOne = async () => {
]) ])
} }
} }
const inoutFocus = async () => {
const inputEl: ComponentRef<typeof ElInput> = await getComponentExpose('field1')
inputEl?.focus()
}
const inoutValidation = async () => {
const formItem = await getFormItemExpose('field1')
const inputEl: ComponentRef<typeof ElInput> = await getComponentExpose('field1')
inputEl?.focus()
formItem?.validate('focus', (val: boolean) => {
console.log(val)
})
}
</script> </script>
<template> <template>
@ -270,6 +294,13 @@ const getDictOne = async () => {
<ElButton @click="getDictOne"> <ElButton @click="getDictOne">
{{ t('searchDemo.dynamicOptions') }} {{ t('searchDemo.dynamicOptions') }}
</ElButton> </ElButton>
<ElButton @click="inoutFocus">
{{ `${t('formDemo.input')} ${t('formDemo.focus')}` }}
</ElButton>
<ElButton @click="inoutValidation">
{{ `${t('formDemo.input')} ${t('formDemo.formValidation')}` }}
</ElButton>
</ContentWrap> </ContentWrap>
<ContentWrap :title="`UseForm ${t('formDemo.example')}`"> <ContentWrap :title="`UseForm ${t('formDemo.example')}`">
<Form :schema="schema" @register="register" /> <Form :schema="schema" @register="register" />