From ebcd7b4552022442ccafd7560423c5ab87af6ddc Mon Sep 17 00:00:00 2001 From: qiang Date: Thu, 19 Dec 2024 17:25:21 +0800 Subject: [PATCH] chore(Form): simplify expose related code --- docs/en-US/components/Crud.md | 2 ++ docs/zh-CN/components/Crud.md | 2 ++ src/Crud/Crud.ts | 66 +++++++++++++++++++---------------- src/Crud/index.test.ts | 9 +++-- src/Crud/type.ts | 2 ++ src/Form/Form.ts | 23 ++---------- src/Form/type.ts | 20 ++--------- src/Form/useForm.ts | 43 ++++++----------------- src/Search/Search.ts | 21 ++--------- src/Search/index.test.ts | 42 ++++++++++++++++++++++ 10 files changed, 110 insertions(+), 120 deletions(-) diff --git a/docs/en-US/components/Crud.md b/docs/en-US/components/Crud.md index 7b79c07e..6789a000 100644 --- a/docs/en-US/components/Crud.md +++ b/docs/en-US/components/Crud.md @@ -459,6 +459,8 @@ Other attributes are the same as | clearValidate | clear validation message for certain fields. The parameter is prop name or an array of prop names of the form items whose validation messages will be removed. When omitted, all fields' validation messages will be cleared | (props?: string \| string[]) => void | | openDialog | open dialog | (type: ICrudDialogType, row?: UnknownObject) => void | | closeDialog | close dialog | () => void | +| searchRef | get the search component instance | IFormExpose | +| formRef | get the form component instance | IFormExpose | ### Slots diff --git a/docs/zh-CN/components/Crud.md b/docs/zh-CN/components/Crud.md index 69f74a1c..5e12aa08 100644 --- a/docs/zh-CN/components/Crud.md +++ b/docs/zh-CN/components/Crud.md @@ -459,6 +459,8 @@ Crud columns 支持 Table columns | clearValidate | 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果 | (props?: string \| string[]) => void | | openDialog | 打开弹窗 | (type: ICrudDialogType, row?: UnknownObject) => void | | closeDialog | 关闭弹窗 | () => void | +| searchRef | 获取搜索表单实例 | IFormExpose | +| formRef | 获取表单实例 | IFormExpose | ### 插槽 diff --git a/src/Crud/Crud.ts b/src/Crud/Crud.ts index 9e402af8..dca55b96 100644 --- a/src/Crud/Crud.ts +++ b/src/Crud/Crud.ts @@ -1,4 +1,13 @@ -import { computed, defineComponent, h, VNode, Slot, mergeProps } from 'vue' +import { + computed, + defineComponent, + h, + VNode, + Slot, + mergeProps, + reactive, + ref, +} from 'vue' import { ElDialog, ElButton, useAttrs, DialogProps } from 'element-plus' import { useBreakpointWidth, useSplitReactive } from '../composables/index' import { @@ -55,16 +64,9 @@ export default defineComponent({ sort, } = useTableMethods() const { sizeChange, currentChange } = usePagination(emit) - const { - formRef, - validate, - resetFields, - clearValidate, - scrollToField, - validateField, - update, - resetForm, - } = useFormMethods(emit as unknown as IFormEmits) + const { formRef, update, resetForm } = useFormMethods( + emit as unknown as IFormEmits, + ) const { showDialog, type, @@ -84,6 +86,24 @@ export default defineComponent({ const attrs = useAttrs() const dialogWidth = useBreakpointWidth() + + const searchRef = ref() + const crudExpose = reactive({ + searchRef, + formRef, + clearSelection, + toggleRowSelection, + toggleAllSelection, + toggleRowExpansion, + setCurrentRow, + clearSort, + clearFilter, + doLayout, + sort, + openDialog, + closeDialog, + }) + const bindDialog = computed(() => { const title = props.title || @@ -117,6 +137,8 @@ export default defineComponent({ } }) + expose(crudExpose) + function checkDetail(row: StringObject) { return isFunction(menuColumns.value.detail) ? menuColumns.value.detail(row) @@ -140,25 +162,6 @@ export default defineComponent({ emit('delete', row) } - expose({ - clearSelection, - toggleRowSelection, - toggleAllSelection, - toggleRowExpansion, - setCurrentRow, - clearSort, - clearFilter, - doLayout, - sort, - validate, - resetFields, - scrollToField, - clearValidate, - validateField, - openDialog, - closeDialog, - }) - function createSearch() { if (props.searchRules) { throwWarn( @@ -167,6 +170,7 @@ export default defineComponent({ } const _props = { + ref: searchRef, rules: props.searchRules, ...props.searchProps, modelValue: props.search, @@ -317,6 +321,8 @@ export default defineComponent({ } function createForm() { + Object.assign(crudExpose, formRef.value) + const _props = mergeProps(formProps, attrs.value, { ref: formRef, columns: formColumns.value, diff --git a/src/Crud/index.test.ts b/src/Crud/index.test.ts index ab705872..2b939b22 100644 --- a/src/Crud/index.test.ts +++ b/src/Crud/index.test.ts @@ -833,6 +833,8 @@ describe('Crud', () => { ref="crudRef" :columns="columns" :data="data" + :menu="{}" + :append-to-body="false" /> `, setup() { @@ -856,13 +858,16 @@ describe('Crud', () => { expect(vm.crudRef.clearFilter).toBeTruthy() expect(vm.crudRef.doLayout).toBeTruthy() expect(vm.crudRef.sort).toBeTruthy() + expect(vm.crudRef.openDialog).toBeTruthy() + expect(vm.crudRef.closeDialog).toBeTruthy() + expect(vm.crudRef.validate).toBeFalsy() + + await wrapper.find(addClass).trigger('click') expect(vm.crudRef.validate).toBeTruthy() expect(vm.crudRef.resetFields).toBeTruthy() expect(vm.crudRef.scrollToField).toBeTruthy() expect(vm.crudRef.clearValidate).toBeTruthy() expect(vm.crudRef.validateField).toBeTruthy() - expect(vm.crudRef.openDialog).toBeTruthy() - expect(vm.crudRef.closeDialog).toBeTruthy() }) }) diff --git a/src/Crud/type.ts b/src/Crud/type.ts index c5823ee1..4ce09497 100644 --- a/src/Crud/type.ts +++ b/src/Crud/type.ts @@ -135,6 +135,8 @@ export type ICrudEmits = IDefineEmits export interface ICrudExpose extends IFormExpose, ITableExpose { + searchRef: IFormExpose + formRef: IFormExpose /** open the dialog */ openDialog: (type: ICrudDialogType, row?: UnknownObject) => void /** close the dialog */ diff --git a/src/Form/Form.ts b/src/Form/Form.ts index 423efcbd..bdeb593b 100644 --- a/src/Form/Form.ts +++ b/src/Form/Form.ts @@ -15,18 +15,8 @@ export default defineComponent({ emits: formEmits, setup(props, { slots, emit, expose }) { const [config] = useSplitReactive(props, formKeys) - const { - formRef, - loading, - validate, - resetFields, - scrollToField, - clearValidate, - validateField, - update, - submitForm, - resetForm, - } = useFormMethods(emit) + const { formRef, formExpose, loading, update, submitForm, resetForm } = + useFormMethods(emit) const menu = useFormMenu(props) const { rowStyle, rowClass } = useRow(props) const breakpoint = useCurrentBreakpoint() @@ -48,14 +38,7 @@ export default defineComponent({ useFormProvide({ props, emit, slots, formRef, disabled }) - expose({ - ...formRef.value, - validate, - resetFields, - scrollToField, - clearValidate, - validateField, - }) + expose(formExpose) function createColumns() { return h( diff --git a/src/Form/type.ts b/src/Form/type.ts index bf09e4d8..6fabda51 100644 --- a/src/Form/type.ts +++ b/src/Form/type.ts @@ -21,12 +21,12 @@ import type { TabPaneProps, CollapseItemProps, StepProps, + FormInstance, } from 'element-plus' import type { IDefineProps, IDefineEmits, UnknownObject, - MaybeArray, ExternalParam, Mutable, ColumnProp, @@ -138,27 +138,13 @@ export interface IFormValidateFieldCallback { } /** Form Expose Methods */ -export interface IFormExpose { - /** validate the whole form. Takes a callback as a param. After validation, the callback will be executed with two params: a boolean indicating if the validation has passed, and an object containing all fields that fail the validation. Returns a promise if callback is omitted */ - validate: (callback?: IFormValidateCallback) => Promise - /** reset all the fields and remove validation result */ - resetFields: () => void - /** Scroll to the specified form field */ - scrollToField: (prop: string) => void - /** clear validation message for certain fields. The parameter is prop name or an array of prop names of the form items whose validation messages will be removed. When omitted, all fields' validation messages will be cleared */ - clearValidate: (props?: MaybeArray) => void - /** validate one or several form items */ - validateField: ( - props: MaybeArray, - cb: IFormValidateFieldCallback, - ) => void -} +export type IFormExpose = FormInstance export interface UseFormProvideConfig { props: IFormProps emit: IFormEmits slots: Readonly - formRef: Ref + formRef: Ref /** disabled submit */ disabled: Ref } diff --git a/src/Form/useForm.ts b/src/Form/useForm.ts index c051dccb..e38ad81c 100644 --- a/src/Form/useForm.ts +++ b/src/Form/useForm.ts @@ -1,14 +1,12 @@ -import { computed, shallowRef, provide, inject } from 'vue' +import { computed, shallowRef, provide, inject, reactive, onMounted } from 'vue' import { useShow, useLocale } from '../composables/index' import { isBoolean } from '../utils/index' import type { ComputedRef, Ref, InjectionKey, Slot } from 'vue' import type { CollapseModelValue, TabPaneName } from 'element-plus' -import type { UnknownObject, MaybeArray } from '../types/index' +import type { UnknownObject } from '../types/index' import type { IFormEmits, IFormExpose, - IFormValidateCallback, - IFormValidateFieldCallback, IFormMenuColumns, InvalidFields, IFormContext, @@ -48,36 +46,19 @@ export function useFormMenu( export function useFormMethods(emit: IFormEmits): { formRef: Ref + formExpose: IFormExpose loading: Ref update: (value: UnknownObject) => void submitForm: () => void resetForm: (reset?: boolean) => void -} & IFormExpose { +} { const formRef = shallowRef({} as IFormExpose) + const formExpose = reactive({} as IFormExpose) const { show, toggleShow } = useShow() - function validate(callback?: IFormValidateCallback) { - return formRef.value.validate(callback) - } - - function resetFields() { - formRef.value.resetFields() - } - - function scrollToField(prop: string) { - formRef.value.scrollToField(prop) - } - - function clearValidate(props?: MaybeArray) { - formRef.value.clearValidate(props) - } - - function validateField( - props: MaybeArray, - cb: IFormValidateFieldCallback, - ) { - formRef.value.validateField(props, cb) - } + onMounted(() => { + Object.assign(formExpose, formRef.value) + }) function update(value?: UnknownObject | UnknownObject[]) { emit('update:modelValue', value) @@ -103,18 +84,14 @@ export function useFormMethods(emit: IFormEmits): { if (isBoolean(reset) && reset) { update(undefined) } - resetFields() + formRef.value?.resetFields() emit('reset') } return { formRef, + formExpose, loading: show, - validate, - resetFields, - scrollToField, - clearValidate, - validateField, update, submitForm, resetForm, diff --git a/src/Search/Search.ts b/src/Search/Search.ts index 5075e91a..9cd2632c 100644 --- a/src/Search/Search.ts +++ b/src/Search/Search.ts @@ -24,26 +24,11 @@ export default defineComponent({ stepChange, submitForm, } = useSearch(props, emit) - const { - formRef, - validate, - resetFields, - clearValidate, - scrollToField, - validateField, - update, - resetForm, - } = useFormMethods(emit) + const { formRef, formExpose, update, resetForm } = useFormMethods(emit) + useSearchMenuWidth(formRef) - expose({ - ...formRef.value, - validate, - resetFields, - scrollToField, - clearValidate, - validateField, - }) + expose(formExpose) return () => h( diff --git a/src/Search/index.test.ts b/src/Search/index.test.ts index 64a742de..b71704e8 100644 --- a/src/Search/index.test.ts +++ b/src/Search/index.test.ts @@ -136,6 +136,48 @@ describe('ProSearch', () => { wrapper.unmount() }) + + test.concurrent('expose', async () => { + const wrapper = await mount({ + template: ` + `, + setup() { + const search = ref({}) + const searchRef = ref() + const searchItemRef = ref() + const inputRef = ref() + const _columns = [ + { + ...columns[0], + ref: searchItemRef, + props: { ref: inputRef }, + }, + ] + return { search, columns: _columns, searchRef, searchItemRef, inputRef } + }, + }) + + expect(wrapper.find('.el-input').exists()).toBe(true) + expect(Object.keys(wrapper.vm.inputRef)).not.toHaveLength(0) + expect(wrapper.vm.inputRef).toHaveProperty('focus') + expect(wrapper.vm.inputRef).toHaveProperty('blur') + + expect(Object.keys(wrapper.vm.searchItemRef)).not.toHaveLength(0) + expect(wrapper.vm.searchItemRef).toHaveProperty('validate') + expect(wrapper.vm.searchItemRef).toHaveProperty('resetField') + expect(wrapper.vm.searchItemRef).toHaveProperty('clearValidate') + expect(wrapper.vm.searchItemRef).toHaveProperty('validateState') + + expect(Object.keys(wrapper.vm.searchRef)).not.toHaveLength(0) + expect(wrapper.vm.searchRef).toHaveProperty('validate') + expect(wrapper.vm.searchRef).toHaveProperty('validateField') + expect(wrapper.vm.searchRef).toHaveProperty('resetFields') + expect(wrapper.vm.searchRef).toHaveProperty('clearValidate') + }) }) afterAll(() => {