ArrayTable
自增表格,对于数据量超大的场景比较适合使用该组件,重构后的 ArrayTable 组件性能大幅提升,大数量时输入时也不会有卡顿。
注意
该组件只适用于 Schema 场景,且只能是对象数组。
提示
由于需要给分页添加错误提示,本组件内置的分页组件fork了2.9.11版本的element-plus的分页组件,如果没有特殊情况内置的分页组件将不再更新,配置项属性请以该版本的为准,组件内部的函数还是从peerDependencies中获取,所以语言可以正常的从element-plus中继承。需要修改默认语言请使用el-config-provider组件进行包裹。
提示
目前有一个已知的bug即表格校验时不会校验尚未渲染过的行,这是formily的一个bug,所以使用react组件库封装时也会有类似的问题。即通过方法添加10w条数据时不会校验没渲染过的分页,点击过分页后才会校验。但是通过添加按钮添加时会自动切换到下一页保证数据是经过渲染的,因此尽量使用添加按钮添加数据。
Markup Schema 案例
vue
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
} from '@silver-formily/element-plus'
import { ElAlert, ElButton } from 'element-plus'
const form = createForm()
const {
SchemaField,
SchemaArrayField,
SchemaObjectField,
SchemaVoidField,
SchemaStringField,
} = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Space,
},
})
async function log(...v) {
console.log(...v)
}
function range(count) {
return Array.from({ length: count }).map(_ => ({ a1: null, a2: null, a3: null }))
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaArrayField
name="array"
x-decorator="FormItem"
x-component="ArrayTable"
:x-component-props="{
stripe: true,
paginationProps: { pageSize: 10 },
}"
>
<SchemaObjectField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ width: 80, title: 'Index' }"
>
<SchemaVoidField
x-decorator="FormItem"
x-component="ArrayTable.Index"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ prop: 'a1', title: 'A1', width: 200 }"
>
<SchemaStringField
x-decorator="Editable"
name="a1"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ title: 'A2', width: 200 }"
>
<SchemaStringField
x-decorator="FormItem"
:x-decorator-props="{
feedbackLayout: 'popover',
}"
name="a2"
:required="true"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ title: 'A3' }"
>
<SchemaStringField
name="a3"
:required="true"
x-decorator="FormItem"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
}"
>
<SchemaVoidField x-component="FormItem">
<SchemaVoidField x-component="Space" :x-component-props="{ style: 'height: 100%' }">
<SchemaVoidField x-component="ArrayTable.Remove" />
<SchemaVoidField x-component="ArrayTable.MoveUp" />
<SchemaVoidField x-component="ArrayTable.MoveDown" />
</SchemaVoidField>
</SchemaVoidField>
</SchemaVoidField>
</SchemaObjectField>
<SchemaVoidField x-component="ArrayTable.Addition" :x-component-props="{ defaultValue: { a1: null, a2: '', a3: '' } }" title="添加条目" />
</SchemaArrayField>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
<ElButton
@click="
() => {
form.setInitialValues({
array: range(100000),
})
}
"
>
加载10W条超大数据
</ElButton>
<ElAlert
:style="{ marginTop: '10px' }"
title="注意:开启formily插件的页面,因为后台有数据通信,会占用浏览器算力,最好在无痕模式(无formily插件)下测试"
type="warning"
/>
</FormProvider>
</template>Markup Schema 关闭分页案例
vue
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Select,
Space,
Submit,
} from '@silver-formily/element-plus'
const form = createForm()
const {
SchemaField,
SchemaArrayField,
SchemaObjectField,
SchemaVoidField,
SchemaStringField,
} = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Select,
Editable,
Space,
},
})
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaArrayField
name="array"
x-decorator="FormItem"
x-component="ArrayTable"
:x-component-props="{
pagination: false,
height: 300,
}"
>
<SchemaObjectField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ width: 80, title: 'Index' }"
>
<SchemaVoidField
x-decorator="FormItem"
x-component="ArrayTable.Index"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ prop: 'a1', title: 'A1' }"
>
<SchemaStringField
x-decorator="Editable"
name="a1"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ prop: 'a2', title: 'A2' }"
>
<SchemaStringField
x-decorator="Editable"
name="a2"
x-component="Select"
:x-decorator-props="{
editProps: {
style: { width: '300px' },
},
}"
:enum="[
{ label: 'Option 1', value: 'option1' },
{ label: 'Option 2', value: 'option2' },
{ label: 'Option 3', value: 'option3' },
]"
default="option1"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
}"
>
<SchemaVoidField x-component="FormItem">
<SchemaVoidField x-component="Space" :x-component-props="{ style: 'height: 100%' }">
<SchemaVoidField x-component="ArrayTable.Remove" />
<SchemaVoidField x-component="ArrayTable.MoveUp" />
<SchemaVoidField x-component="ArrayTable.MoveDown" />
</SchemaVoidField>
</SchemaVoidField>
</SchemaVoidField>
</SchemaObjectField>
<SchemaVoidField x-component="ArrayTable.Addition" :x-component-props="{ defaultValue: { a1: null, a2: '', a3: '' } }" title="添加条目" />
</SchemaArrayField>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>Markup Schema 可拖拽案例
vue
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
} from '@silver-formily/element-plus'
function range(count) {
return Array.from({ length: count }).map((_, index) => ({ a1: index }))
}
const form = createForm({
initialValues: {
array: range(30),
},
})
const {
SchemaField,
SchemaArrayField,
SchemaObjectField,
SchemaVoidField,
SchemaStringField,
} = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Space,
},
})
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaArrayField
name="array"
x-decorator="FormItem"
x-component="ArrayTable"
:x-component-props="{
stripe: true,
}"
>
<SchemaObjectField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ width: 60 }"
>
<SchemaVoidField
x-decorator="FormItem"
x-component="ArrayTable.SortHandle"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ width: 80, title: 'Index' }"
>
<SchemaVoidField
x-decorator="FormItem"
x-component="ArrayTable.Index"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{ prop: 'a1', title: 'A1' }"
>
<SchemaStringField
x-decorator="Editable"
name="a1"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
:x-component-props="{
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
}"
>
<SchemaVoidField x-component="FormItem">
<SchemaVoidField x-component="Space" :x-component-props="{ style: 'height: 100%' }">
<SchemaVoidField x-component="ArrayTable.Remove" />
<SchemaVoidField x-component="ArrayTable.MoveUp" />
<SchemaVoidField x-component="ArrayTable.MoveDown" />
</SchemaVoidField>
</SchemaVoidField>
</SchemaVoidField>
</SchemaObjectField>
<SchemaVoidField x-component="ArrayTable.Addition" :x-component-props="{ defaultValue: { a1: null, a2: '', a3: '' } }" title="添加条目" />
</SchemaArrayField>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>JSON Schema 案例
vue
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
} from '@silver-formily/element-plus'
const { SchemaField } = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Space,
},
})
const form = createForm()
const schema = {
type: 'object',
properties: {
array: {
'type': 'array',
'x-decorator': 'FormItem',
'x-component': 'ArrayTable',
'items': {
type: 'object',
properties: {
column1: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
width: 80,
title: 'Index',
align: 'center',
},
'properties': {
index: {
'type': 'void',
'x-component': 'ArrayTable.Index',
},
},
},
column2: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 200, title: 'A1' },
'properties': {
a1: {
'type': 'string',
'x-decorator': 'Editable',
'x-component': 'Input',
},
},
},
column3: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 200, title: 'A2' },
'properties': {
a2: {
'type': 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column4: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: 'A3' },
'properties': {
a3: {
'type': 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column5: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
},
'properties': {
item: {
'type': 'void',
'x-component': 'FormItem',
'properties': {
space: {
'type': 'void',
'x-component': 'Space',
'x-component-props': {
style: 'height: 100%',
},
'properties': {
remove: {
'type': 'void',
'x-component': 'ArrayTable.Remove',
},
moveDown: {
'type': 'void',
'x-component': 'ArrayTable.MoveDown',
},
moveUp: {
'type': 'void',
'x-component': 'ArrayTable.MoveUp',
},
},
},
},
},
},
},
},
},
'properties': {
add: {
'type': 'void',
'x-component': 'ArrayTable.Addition',
'title': '添加条目',
},
},
},
},
}
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField :schema="schema" />
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>JSON Schema 修改分页配置案例
vue
<script lang="ts" setup>
import { createForm } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
} from '@silver-formily/element-plus'
const { SchemaField } = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Space,
},
})
const form = createForm()
const schema = {
type: 'object',
properties: {
array: {
'type': 'array',
'x-decorator': 'FormItem',
'x-component': 'ArrayTable',
'x-component-props': {
paginationProps: {
pageSize: 2,
pageSizes: [2, 4, 6, 8, 10],
background: false,
size: 'small',
},
},
'items': {
type: 'object',
properties: {
column1: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
width: 80,
title: 'Index',
align: 'center',
},
'properties': {
index: {
'type': 'void',
'x-component': 'ArrayTable.Index',
},
},
},
column2: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: 'A1' },
'properties': {
a1: {
'type': 'string',
'x-decorator': 'Editable',
'x-component': 'Input',
},
},
},
column3: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
},
'properties': {
item: {
'type': 'void',
'x-component': 'FormItem',
'properties': {
space: {
'type': 'void',
'x-component': 'Space',
'x-component-props': {
style: 'height: 100%',
},
'properties': {
remove: {
'type': 'void',
'x-component': 'ArrayTable.Remove',
},
moveDown: {
'type': 'void',
'x-component': 'ArrayTable.MoveDown',
},
moveUp: {
'type': 'void',
'x-component': 'ArrayTable.MoveUp',
},
},
},
},
},
},
},
},
},
'properties': {
add: {
'type': 'void',
'x-component': 'ArrayTable.Addition',
'title': '添加条目',
},
},
},
},
}
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField :schema="schema" />
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>Effects 联动案例
vue
<script lang="ts" setup>
import { createForm, isField, onFieldChange, onFieldReact } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
Switch,
} from '@silver-formily/element-plus'
const {
SchemaField,
SchemaArrayField,
SchemaObjectField,
SchemaVoidField,
SchemaStringField,
SchemaBooleanField,
} = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Switch,
Space,
},
})
const form = createForm({
effects: () => {
// 主动联动模式
onFieldChange('hideFirstColumn', ['value'], (field) => {
field.query('array.column3').take((target) => {
if (isField(field)) {
target.visible = !field.value
}
})
field.query('array.*.a2').take((target) => {
if (isField(field)) {
target.visible = !field.value
}
})
})
// 被动联动模式
onFieldReact('array.*.a2', (field) => {
field.visible = !field.query('.a1').get('value')
})
},
})
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField>
<SchemaBooleanField
name="hideFirstColumn"
x-decorator="FormItem"
x-component="Switch"
title="隐藏A2"
/>
<SchemaArrayField
name="array"
x-decorator="FormItem"
x-component="ArrayTable"
>
<SchemaObjectField>
<SchemaVoidField
name="column1"
x-component="ArrayTable.Column"
:x-component-props="{ width: 80, title: 'Index' }"
>
<SchemaVoidField x-component="ArrayTable.Index" />
</SchemaVoidField>
<SchemaVoidField
name="column2"
x-component="ArrayTable.Column"
:x-component-props="{
title: '显隐->A2',
width: 100,
}"
>
<SchemaBooleanField
name="a1"
x-decorator="FormItem"
x-component="Switch"
/>
</SchemaVoidField>
<SchemaVoidField
x-component="ArrayTable.Column"
name="column3"
:x-component-props="{ title: 'A2', width: 200 }"
>
<SchemaStringField
x-decorator="FormItem"
name="a2"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
name="column4"
x-component="ArrayTable.Column"
:x-component-props="{ title: 'A3' }"
>
<SchemaStringField
name="a3"
x-decorator="FormItem"
x-component="Input"
/>
</SchemaVoidField>
<SchemaVoidField
name="column5"
x-component="ArrayTable.Column"
:x-component-props="{
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
}"
>
<SchemaVoidField x-component="FormItem">
<SchemaVoidField x-component="Space" :x-component-props="{ style: 'height: 100%' }">
<SchemaVoidField x-component="ArrayTable.Remove" />
<SchemaVoidField x-component="ArrayTable.MoveUp" />
<SchemaVoidField x-component="ArrayTable.MoveDown" />
</SchemaVoidField>
</SchemaVoidField>
</SchemaVoidField>
</SchemaObjectField>
<SchemaVoidField x-component="ArrayTable.Addition" title="添加条目" />
</SchemaArrayField>
</SchemaField>
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>JSON Schema 联动案例
vue
<script lang="ts" setup>
import { createForm, isField, onFieldChange, onFieldReact } from '@formily/core'
import { createSchemaField, FormProvider } from '@formily/vue'
import {
ArrayTable,
Editable,
FormItem,
Input,
Space,
Submit,
Switch,
} from '@silver-formily/element-plus'
const { SchemaField } = createSchemaField({
components: {
FormItem,
ArrayTable,
Input,
Editable,
Switch,
Space,
},
})
const form = createForm({
effects: () => {
// 主动联动模式
onFieldChange('hideFirstColumn', ['value'], (field) => {
field.query('array.column3').take((target) => {
if (isField(field)) {
target.visible = !field.value
}
})
field.query('array.*.a2').take((target) => {
if (isField(field)) {
target.visible = !field.value
}
})
})
// 被动联动模式
onFieldReact('array.*.a2', (field) => {
field.visible = !field.query('.a1').get('value')
})
},
})
const schema = {
type: 'object',
properties: {
hideFirstColumn: {
'type': 'boolean',
'title': '隐藏A2',
'x-decorator': 'FormItem',
'x-component': 'Switch',
},
array: {
'type': 'array',
'x-decorator': 'FormItem',
'x-component': 'ArrayTable',
'items': {
type: 'object',
properties: {
column1: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
width: 80,
title: 'Index',
align: 'center',
},
'properties': {
index: {
'type': 'void',
'x-component': 'ArrayTable.Index',
},
},
},
column2: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 100, title: '显隐->A2' },
'properties': {
a1: {
'type': 'boolean',
'x-decorator': 'FormItem',
'x-component': 'Switch',
},
},
},
column3: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 200, title: 'A2' },
'properties': {
a2: {
'type': 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column4: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: 'A3' },
'properties': {
a3: {
'type': 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column5: {
'type': 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
title: 'Operations',
prop: 'operations',
width: 200,
fixed: 'right',
},
'properties': {
item: {
'type': 'void',
'x-component': 'FormItem',
'properties': {
space: {
'type': 'void',
'x-component': 'Space',
'x-component-props': {
style: 'height: 100%',
},
'properties': {
remove: {
'type': 'void',
'x-component': 'ArrayTable.Remove',
},
moveDown: {
'type': 'void',
'x-component': 'ArrayTable.MoveDown',
},
moveUp: {
'type': 'void',
'x-component': 'ArrayTable.MoveUp',
},
},
},
},
},
},
},
},
},
'properties': {
add: {
'type': 'void',
'x-component': 'ArrayTable.Addition',
'title': '添加条目',
},
},
},
},
}
async function log(...v) {
console.log(...v)
}
</script>
<template>
<FormProvider :form="form">
<SchemaField :schema="schema" />
<Submit @submit="log">
提交
</Submit>
</FormProvider>
</template>API
ArrayTable
表格组件
参考 https://cn.element-plus.org/zh-CN/component/table.html
扩展属性
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| pagination | boolean | 是否启用分页 | true |
| paginationProps | object | 分页组件属性 | { backgound: true, layout: "total, sizes, prev, pager, next" } |
ArrayTable.Column
表格列
参考 https://cn.element-plus.org/zh-CN/component/table.html
扩展属性
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| asterisk | boolean | 星号显示 | true |
提示
- ArrayTableColumn 会自动检查内部的 FormItem 是否必填,并自动在表头加上红色星号。如果不希望显示,可通过
asterisk属性进行覆盖。 - AtrrayTableColumn 仅继承属性,不支持插槽。
ArrayTable.SortHandle
参考ArrayBase.SortHandle
ArrayTable.Addition
参考ArrayBase.Addition