perf: 优化Form事件传递

This commit is contained in:
kailong321200875 2023-06-27 09:49:07 +08:00
parent 24c8af9183
commit 69cafb3b7b
6 changed files with 53 additions and 228 deletions

View File

@ -1,6 +1,6 @@
<script lang="tsx"> <script lang="tsx">
import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue' import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue'
import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus' import { ElForm, ElFormItem, ElRow, ElCol, FormItemProp } from 'element-plus'
import { componentMap } from './helper/componentMap' import { componentMap } from './helper/componentMap'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { getSlot } from '@/utils/tsxHelper' import { getSlot } from '@/utils/tsxHelper'
@ -57,7 +57,7 @@ export default defineComponent({
// label // label
labelWidth: propTypes.oneOfType([String, Number]).def('auto') labelWidth: propTypes.oneOfType([String, Number]).def('auto')
}, },
emits: ['register'], emits: ['register', 'validate'],
setup(props, { slots, expose, emit }) { setup(props, { slots, expose, emit }) {
// element form // element form
const elFormRef = ref<ComponentRef<typeof ElForm>>() const elFormRef = ref<ComponentRef<typeof ElForm>>()
@ -339,12 +339,17 @@ export default defineComponent({
return props return props
} }
const onValidate = (prop: FormItemProp, isValid: boolean, message: string) => {
emit('validate', prop, isValid, message)
}
return () => ( return () => (
<ElForm <ElForm
ref={elFormRef} ref={elFormRef}
{...getFormBindValue()} {...getFormBindValue()}
model={unref(getProps).isCustom ? unref(getProps).model : formModel} model={unref(getProps).isCustom ? unref(getProps).model : formModel}
class={prefixCls} class={prefixCls}
onValidate={onValidate}
> >
{{ {{
// //

View File

@ -8,6 +8,7 @@ import { cloneDeep, set } from 'lodash-es'
import { initModel } from '@/components/Form/src/helper' import { initModel } from '@/components/Form/src/helper'
import ActionButton from './components/ActionButton.vue' import ActionButton from './components/ActionButton.vue'
import { SearchProps } from './types' import { SearchProps } from './types'
import { FormItemProp } from 'element-plus'
const props = defineProps({ const props = defineProps({
// Form // Form
@ -42,7 +43,7 @@ const props = defineProps({
resetLoading: propTypes.bool.def(false) resetLoading: propTypes.bool.def(false)
}) })
const emit = defineEmits(['search', 'reset', 'register']) const emit = defineEmits(['search', 'reset', 'register', 'validate'])
const visible = ref(true) const visible = ref(true)
@ -214,6 +215,10 @@ onMounted(() => {
}) })
defineExpose(defaultExpose) defineExpose(defaultExpose)
const onFormValidate = (prop: FormItemProp, isValid: boolean, message: string) => {
emit('validate', prop, isValid, message)
}
</script> </script>
<template> <template>
@ -226,6 +231,7 @@ defineExpose(defaultExpose)
:is-col="getProps.isCol" :is-col="getProps.isCol"
:schema="newSchema" :schema="newSchema"
@register="formRegister" @register="formRegister"
@validate="onFormValidate"
/> />
<template v-if="layout === 'bottom'"> <template v-if="layout === 'bottom'">

View File

@ -182,7 +182,7 @@ export default defineComponent({
) : undefined ) : undefined
} }
const rnderTreeTableColumn = (columnsChildren: TableColumn[]) => { const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
const { align, headerAlign, showOverflowTooltip } = unref(getProps) const { align, headerAlign, showOverflowTooltip } = unref(getProps)
return columnsChildren.map((v) => { return columnsChildren.map((v) => {
const props = { ...v } const props = { ...v }
@ -198,7 +198,7 @@ export default defineComponent({
{{ {{
default: (data: TableSlotDefault) => default: (data: TableSlotDefault) =>
v.children && v.children.length v.children && v.children.length
? rnderTableColumn(v.children) ? renderTableColumn(v.children)
: // @ts-ignore : // @ts-ignore
getSlot(slots, v.field, data) || getSlot(slots, v.field, data) ||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) || v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
@ -211,7 +211,7 @@ export default defineComponent({
}) })
} }
const rnderTableColumn = (columnsChildren?: TableColumn[]) => { const renderTableColumn = (columnsChildren?: TableColumn[]) => {
const { const {
columns, columns,
reserveIndex, reserveIndex,
@ -253,7 +253,7 @@ export default defineComponent({
{{ {{
default: (data: TableSlotDefault) => default: (data: TableSlotDefault) =>
v.children && v.children.length v.children && v.children.length
? rnderTreeTableColumn(v.children) ? renderTreeTableColumn(v.children)
: // @ts-ignore : // @ts-ignore
getSlot(slots, v.field, data) || getSlot(slots, v.field, data) ||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) || v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
@ -278,7 +278,7 @@ export default defineComponent({
{...unref(getBindValue)} {...unref(getBindValue)}
> >
{{ {{
default: () => rnderTableColumn(), default: () => renderTableColumn(),
// @ts-ignore // @ts-ignore
append: () => getSlot(slots, 'append') append: () => getSlot(slots, 'append')
}} }}

View File

@ -159,42 +159,34 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
} }
] ]
}, },
// { {
// path: 'table', path: 'table',
// component: getParentLayout(), component: getParentLayout(),
// redirect: '/components/table/default-table', redirect: '/components/table/default-table',
// name: 'TableDemo', name: 'TableDemo',
// meta: { meta: {
// title: t('router.table'), title: t('router.table'),
// alwaysShow: true alwaysShow: true
// }, },
// children: [ children: [
// { {
// path: 'default-table', path: 'default-table',
// component: () => import('@/views/Components/Table/DefaultTable.vue'), component: () => import('@/views/Components/Table/DefaultTable.vue'),
// name: 'DefaultTable', name: 'DefaultTable',
// meta: { meta: {
// title: t('router.defaultTable') title: t('router.defaultTable')
// } }
// }, }
// { // {
// path: 'use-table', // path: 'use-table',
// component: () => import('@/views/Components/Table/UseTableDemo.vue'), // component: () => import('@/views/Components/Table/UseTableDemo.vue'),
// name: 'UseTable', // name: 'UseTable',
// meta: { // meta: {
// title: 'UseTable' // title: 'UseTable'
// } // }
// }, // }
// { ]
// path: 'ref-table', },
// component: () => import('@/views/Components/Table/RefTable.vue'),
// name: 'RefTable',
// meta: {
// title: 'RefTable'
// }
// }
// ]
// },
{ {
path: 'editor-demo', path: 'editor-demo',
component: getParentLayout(), component: getParentLayout(),

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, ElInput } from 'element-plus' import { ElButton, ElInput, FormItemProp } 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'
@ -257,6 +257,10 @@ const inoutValidation = async () => {
console.log(val) console.log(val)
}) })
} }
const formValidate = (prop: FormItemProp, isValid: boolean, message: string) => {
console.log(prop, isValid, message)
}
</script> </script>
<template> <template>
@ -301,7 +305,7 @@ const inoutValidation = async () => {
</ElButton> </ElButton>
</ContentWrap> </ContentWrap>
<ContentWrap :title="`UseForm ${t('formDemo.example')}`"> <ContentWrap :title="`UseForm ${t('formDemo.example')}`">
<Form :schema="schema" @register="formRegister" /> <Form :schema="schema" @register="formRegister" @validate="formValidate" />
</ContentWrap> </ContentWrap>
</template> </template>

View File

@ -1,182 +0,0 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { Table, TableExpose } from '@/components/Table'
import { getTableListApi } from '@/api/table'
import { TableData } from '@/api/table/types'
import { ref, h, reactive, unref } from 'vue'
import { ElTag, ElButton } from 'element-plus'
import { useTable } from '@/hooks/web/useTable'
import { Pagination, TableColumn, TableSlotDefault } from '@/types/table'
const { t } = useI18n()
const columns = reactive<TableColumn[]>([
{
field: 'index',
label: t('tableDemo.index'),
type: 'index'
},
{
field: 'content',
label: t('tableDemo.header'),
children: [
{
field: 'title',
label: t('tableDemo.title')
},
{
field: 'author',
label: t('tableDemo.author')
},
{
field: 'display_time',
label: t('tableDemo.displayTime')
},
{
field: 'importance',
label: t('tableDemo.importance'),
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
return h(
ElTag,
{
type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
},
() =>
cellValue === 1
? t('tableDemo.important')
: cellValue === 2
? t('tableDemo.good')
: t('tableDemo.commonly')
)
}
},
{
field: 'pageviews',
label: t('tableDemo.pageviews')
}
]
},
{
field: 'action',
label: t('tableDemo.action')
}
])
const { register, tableObject, methods } = useTable<TableData>({
getListApi: getTableListApi,
response: {
list: 'list',
total: 'total'
},
props: {
columns
}
})
const { getList } = methods
getList()
const tableRef = ref<TableExpose>()
const actionFn = (data: TableSlotDefault) => {
console.log(data)
}
const paginationObj = ref<Pagination>()
const showPagination = (show: boolean) => {
if (show) {
paginationObj.value = {
total: tableObject.total
}
} else {
paginationObj.value = undefined
}
}
const reserveIndex = (custom: boolean) => {
unref(tableRef)?.setProps({
reserveIndex: custom
})
}
const showSelections = (show: boolean) => {
unref(tableRef)?.setProps({
selection: show
})
}
const index = ref(1)
const changeTitle = () => {
unref(tableRef)?.setColumn([
{
field: 'title',
path: 'label',
value: `${t('tableDemo.title')}${unref(index)}`
}
])
index.value++
}
const showExpandedRows = (show: boolean) => {
unref(tableRef)?.setProps({
expand: show
})
}
const selectAllNone = () => {
unref(tableRef)?.elTableRef?.toggleAllSelection()
}
</script>
<template>
<ContentWrap :title="`RefTable ${t('tableDemo.operate')}`">
<ElButton @click="showPagination(true)">
{{ t('tableDemo.show') }} {{ t('tableDemo.pagination') }}
</ElButton>
<ElButton @click="showPagination(false)">
{{ t('tableDemo.hidden') }} {{ t('tableDemo.pagination') }}
</ElButton>
<ElButton @click="reserveIndex(true)">{{ t('tableDemo.reserveIndex') }}</ElButton>
<ElButton @click="reserveIndex(false)">{{ t('tableDemo.restoreIndex') }}</ElButton>
<ElButton @click="showSelections(true)">{{ t('tableDemo.showSelections') }}</ElButton>
<ElButton @click="showSelections(false)">{{ t('tableDemo.hiddenSelections') }}</ElButton>
<ElButton @click="changeTitle">{{ t('tableDemo.changeTitle') }}</ElButton>
<ElButton @click="showExpandedRows(true)">{{ t('tableDemo.showExpandedRows') }}</ElButton>
<ElButton @click="showExpandedRows(false)">{{ t('tableDemo.hiddenExpandedRows') }}</ElButton>
<ElButton @click="selectAllNone">{{ t('tableDemo.selectAllNone') }}</ElButton>
</ContentWrap>
<ContentWrap :title="`RefTable ${t('tableDemo.example')}`">
<Table
ref="tableRef"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="paginationObj"
@register="register"
>
<template #action="data">
<ElButton type="primary" @click="actionFn(data as TableSlotDefault)">
{{ t('tableDemo.action') }}
</ElButton>
</template>
<template #expand="data">
<div class="ml-30px">
<div>{{ t('tableDemo.title') }}{{ data.row.title }}</div>
<div>{{ t('tableDemo.author') }}{{ data.row.author }}</div>
<div>{{ t('tableDemo.displayTime') }}{{ data.row.display_time }}</div>
</div>
</template>
</Table>
</ContentWrap>
</template>