Skip to content

Commit

Permalink
feat(element): improve performance of ArrayTable (#2678)
Browse files Browse the repository at this point in the history
  • Loading branch information
muuyao authored Dec 27, 2021
1 parent ca55e48 commit b1f1b4e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 113 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Component } from 'vue'
import { merge } from '@formily/shared'
import { h } from '@formily/vue'
import { isVue2, h as hInVue2, defineComponent } from 'vue-demi'
import { isVue2, defineComponent } from 'vue-demi'

type ListenersTransformRules = Record<string, string>

Expand Down
2 changes: 1 addition & 1 deletion packages/element/src/array-items/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface IArrayItemsItemProps {
const ArrayItemsInner = observer(
defineComponent({
name: 'FArrayItems',
setup(props, { attrs }) {
setup() {
const fieldRef = useField<ArrayField>()
const schemaRef = useFieldSchema()

Expand Down
220 changes: 111 additions & 109 deletions packages/element/src/array-table/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
defineComponent,
onBeforeUnmount,
ref,
Ref,
shallowRef,
} from '@vue/composition-api'
import { observe } from '@formily/reactive'
import { computed, defineComponent, ref, Ref } from '@vue/composition-api'
import {
GeneralField,
IVoidFieldFactoryProps,
Expand All @@ -18,10 +11,9 @@ import {
RecursionField as _RecursionField,
h,
Fragment,
useForm,
} from '@formily/vue'
import { observer } from '@formily/reactive-vue'
import { FormPath, isArr, isBool } from '@formily/shared'
import { isArr, isBool } from '@formily/shared'
import { ArrayBase } from '../array-base'
import { stylePrefix } from '../__builtins__/configs'
import { composeExport } from '../__builtins__/shared'
Expand Down Expand Up @@ -64,7 +56,9 @@ interface ObservableColumnSource {
type ColumnProps = ElColumnProps & {
key: string | number
asterisk: boolean
render?: (props: {
render?: (
startIndex: Ref<number>
) => (props: {
row: Record<string, any>
column: ElColumnProps
$index: number
Expand Down Expand Up @@ -147,7 +141,6 @@ const getArrayTableSources = (
}

const getArrayTableColumns = (
reactiveDataSource: Ref<any[]>,
sources: ObservableColumnSource[]
): ColumnProps[] => {
return sources.reduce(
Expand All @@ -160,16 +153,16 @@ const getArrayTableColumns = (
if (display !== 'visible') return buf
if (!isColumnComponent(schema)) return buf

const render =
columnProps?.type && columnProps?.type !== 'default'
const render = (startIndex?: Ref<number>) => {
return columnProps?.type && columnProps?.type !== 'default'
? undefined
: (props: {
row: Record<string, any>
column: ElColumnProps
$index: number
}): VNode => {
// let index = props.$index
const index = reactiveDataSource.value.indexOf(props.row)
let index = (startIndex.value ?? 0) + props.$index
// const index = reactiveDataSource.value.indexOf(props.row)

const children = h(
ArrayBase.Item,
Expand All @@ -191,6 +184,8 @@ const getArrayTableColumns = (
)
return children
}
}

return buf.concat({
label: title,
...props,
Expand Down Expand Up @@ -223,6 +218,10 @@ const renderAddition = () => {
}, null)
}

const schedulerRequest = {
request: null,
}

const StatusSelect = observer(
defineComponent({
props: {
Expand All @@ -232,24 +231,19 @@ const StatusSelect = observer(
pageSize: Number,
},
setup(props) {
const formRef = useForm()
const fieldRef = useField<ArrayField>()
const prefixCls = `${stylePrefix}-array-table`
const width = String(props.options?.length).length * 15

return () => {
const form = formRef.value
const field = fieldRef.value

const errors = form.queryFeedbacks({
type: 'error',
address: `${field.address}.*`,
})
const createIndexPattern = (page: number) => {
const pattern = `${field.address}.*[${(page - 1) * props.pageSize}:${
page * props.pageSize
}].*`
return FormPath.parse(pattern)
const width = String(props.options?.length).length * 15
const errors = field.errors
const parseIndex = (address: string) => {
return Number(
address
.slice(address.indexOf(field.address.toString()) + 1)
.match(/(\d+)/)?.[1]
)
}

return h(
Expand All @@ -276,7 +270,10 @@ const StatusSelect = observer(
default: () => {
return props.options?.map(({ label, value }) => {
const hasError = errors.some(({ address }) => {
return createIndexPattern(value).match(address)
const currentIndex = parseIndex(address)
const startIndex = (value - 1) * props.pageSize
const endIndex = value * props.pageSize
return currentIndex >= startIndex && currentIndex <= endIndex
})

return h(
Expand Down Expand Up @@ -312,93 +309,103 @@ const StatusSelect = observer(
)
}
},
})
}),
{
scheduler: (update) => {
clearTimeout(schedulerRequest.request)
schedulerRequest.request = setTimeout(() => {
update()
}, 100)
},
}
)

const ArrayTablePagination = defineComponent<IArrayTablePaginationProps>({
inheritAttrs: false,
props: [],
props: ['pageSize', 'dataSource'],
setup(props, { attrs, slots }) {
const prefixCls = `${stylePrefix}-array-table`
const current = ref(1)
return () => {
const props = attrs as unknown as IArrayTablePaginationProps
const pageSize = props.pageSize || 10
const dataSource = props.dataSource || []
const startIndex = (current.value - 1) * pageSize
const endIndex = startIndex + pageSize - 1
const total = dataSource?.length || 0
const totalPage = Math.ceil(total / pageSize)
const pages = Array.from(new Array(totalPage)).map((_, index) => {
const pageSize = computed(() => props.pageSize || 10)
const dataSource = computed(() => props.dataSource || [])
const startIndex = computed(() => (current.value - 1) * pageSize.value)
const endIndex = computed(() => startIndex.value + pageSize.value - 1)
const total = computed(() => dataSource.value?.length || 0)
const totalPage = computed(() => Math.ceil(total.value / pageSize.value))
const pages = computed(() => {
return Array.from(new Array(totalPage.value)).map((_, index) => {
const page = index + 1
return {
label: page,
value: page,
}
})
})

const renderPagination = function () {
if (totalPage <= 1) return
return h(
'div',
{
class: [`${prefixCls}-pagination`],
},
{
default: () =>
h(
Space,
{},
{
default: () => [
h(
StatusSelect,
{
props: {
value: current.value,
onChange: (val: number) => {
current.value = val
},
pageSize,
options: pages,
const renderPagination = function () {
if (totalPage.value <= 1) return
return h(
'div',
{
class: [`${prefixCls}-pagination`],
},
{
default: () =>
h(
Space,
{},
{
default: () => [
h(
StatusSelect,
{
props: {
value: current.value,
onChange: (val: number) => {
current.value = val
},
pageSize: pageSize.value,
options: pages.value,
},
{}
),
h(
Pagination,
{
props: {
background: true,
layout: 'prev, pager, next',
...props,
pageSize,
pageCount: totalPage,
currentPage: current.value,
},
on: {
'current-change': (val: number) => {
current.value = val
},
},
{}
),
h(
Pagination,
{
props: {
background: true,
layout: 'prev, pager, next',
...attrs,
pageSize: pageSize.value,
pageCount: totalPage.value,
currentPage: current.value,
},
on: {
'current-change': (val: number) => {
current.value = val
},
},
{}
),
],
}
),
}
)
}
},
{}
),
],
}
),
}
)
}

return () => {
return h(
Fragment,
{},
{
default: () =>
slots?.default?.(
dataSource?.slice(startIndex, endIndex + 1),
renderPagination
dataSource.value?.slice(startIndex.value, endIndex.value + 1),
renderPagination,
startIndex
),
}
)
Expand All @@ -419,31 +426,20 @@ const ArrayTableInner = observer(
const defaultRowKey = (record: any) => {
return getKey(record)
}
const reactiveDataSource = shallowRef([])

const dispose = observe(
fieldRef.value,
() => {
reactiveDataSource.value = fieldRef.value.value
},
false
)

onBeforeUnmount(dispose)

return () => {
const props = attrs as unknown as IArrayTableProps
const field = fieldRef.value
const dataSource = Array.isArray(field.value) ? field.value.slice() : []
const pagination = props.pagination
const sources = getArrayTableSources(fieldRef, schemaRef)
const columns = getArrayTableColumns(reactiveDataSource, sources)
const columns = getArrayTableColumns(sources)

const renderColumns = () =>
columns.map(({ key, render, asterisk, ...props }) => {
const renderColumns = (startIndex?: Ref<number>) => {
return columns.map(({ key, render, asterisk, ...props }) => {
const children = {} as Record<string, any>
if (render) {
children.default = render
children.default = render(startIndex)
}
if (asterisk) {
children.header = ({ column }: { column: ElColumnProps }) =>
Expand Down Expand Up @@ -471,6 +467,8 @@ const ArrayTableInner = observer(
children
)
})
}

const renderStateManager = () =>
sources.map((column, key) => {
//专门用来承接对Column的状态管理
Expand All @@ -489,7 +487,11 @@ const ArrayTableInner = observer(
)
})

const renderTable = (dataSource?: any[], pager?: () => VNode) => {
const renderTable = (
dataSource?: any[],
pager?: () => VNode,
startIndex?: Ref<number>
) => {
return h(
'div',
{ class: prefixCls },
Expand All @@ -516,7 +518,7 @@ const ArrayTableInner = observer(
},
{
...slots,
default: renderColumns,
default: () => renderColumns(startIndex),
}
),
pager?.(),
Expand Down
2 changes: 1 addition & 1 deletion packages/element/src/array-tabs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineComponent, ref } from '@vue/composition-api'
import { observer } from '@formily/reactive-vue'
import { ArrayField } from '@formily/core'
import { h, useField, useFieldSchema, RecursionField } from '@formily/vue'
import { Tabs, TabPane, Badge, Button } from 'element-ui'
import { Tabs, TabPane, Badge } from 'element-ui'
import { stylePrefix } from '../__builtins__/configs'

import type { Tabs as TabsProps } from 'element-ui'
Expand Down
2 changes: 1 addition & 1 deletion packages/element/src/form-item/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const FormBaseItem = defineComponent<FormItemProps>({
bordered: { default: true },
inset: { default: false },
},
setup(props, { slots, attrs, refs }) {
setup(props, { slots, refs }) {
const active = ref(false)
const deepLayoutRef = useFormLayout()

Expand Down

0 comments on commit b1f1b4e

Please sign in to comment.