表单渲染
表单组件有 2 种自定义方式渲染:
render:完全自定义表单组件渲染,支持 h 函数、jsx/tsxslots:根据配置项的prop生成对应的表单组件插槽,生成规则为{prop},和render函数功能一致
表单标签有 3 种自定义方式进行渲染:
render:完全自定义表单标签渲染,支持 h 函数、jsx/tsxrenderHtml:返回 HTML 字符串渲染表单标签slots:根据配置项的prop生成对应的表单标签插槽,生成规则为{prop}-header,和render函数功能一致
如果同时存在多个方式,只生效一个,优先级从高到低(表单组件和表单标签 同理)。
自定义表单组件 (render)
当 render 渲染的组件不支持 v-model 时,需要手动调用 render 的第二个参数 update 回调把值传给表单。
{
"img": "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
"input": "input 值",
"transfer": [],
"data": "初始值",
"data1": "初始值1"
}
vue
<script lang="ts" setup>
import type { FormColumn } from "@/components/pro/form";
import { ref, h, Fragment } from "vue";
import { ElUpload, ElButton, ElImage, ElInput, ElTransfer } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
img: "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
input: "input 值",
transfer: [],
data: "初始值",
data1: "初始值1",
});
const columns: FormColumn[] = [
{
label: "自定义el-input ",
prop: "input",
elProps: {
// 优先级低于 render 的 props
placeholder: "请输入",
},
render: () => {
return h(ElInput);
},
},
{
label: "自定义 el-transfer",
prop: "transfer",
render: ({ value, update }) => {
interface Option {
key: number;
label: string;
disabled: boolean;
}
const data: Option[] = [];
for (let i = 1; i <= 15; i++) {
data.push({
key: i,
label: `Option ${i}`,
disabled: i % 4 === 0,
});
}
return h(ElTransfer as any, {
data: [...data],
});
},
},
{
label: "上传",
prop: "img",
width: 100,
render({ value, update }) {
// 自定义上传
const handleHttpRequest = async ({ file, onError, onSuccess }: any) => {
try {
onSuccess(file);
} catch (error: any) {
onError(error);
}
return file;
};
return h(Fragment, [
h(ElImage as any, {
src: value,
previewSrcList: [value],
style: value ? { width: "60px", marginRight: "10px" } : {},
}),
h(
ElUpload,
{
action: "",
httpRequest: handleHttpRequest,
onChange: async (data: any) => {
const value = await fileToDataURL(data.raw);
// 当渲染的组件不支持 v-model 时,需要手动调用 render 的 update 回调把值传给表单
update(value);
},
},
() => h(ElButton, () => "点击上传")
),
]);
},
},
{
label: "原生表单(返回VNode)",
prop: "data",
elProps: {
placeholder: "请输入原生表单值",
},
render: ({ value, update }) => {
return h("input", {
// 原生表单需要手动添加 value 值
value: value,
// 当渲染的组件不支持 v-model 时,需要手动调用 render 的 update 回调把值传给表单
onChange: (e: Event) => {
const value = (e.target as HTMLInputElement)?.value;
update(value);
},
style: {
border: "1px solid #ccc",
width: "200px",
padding: "0 10px",
},
});
},
},
{
label: "原生标签(返回字符串)",
prop: "data1",
elProps: {
placeholder: "请输入原生表单值",
onChange(e: Event) {
const value = (e?.target as HTMLInputElement)?.value;
return value;
},
},
render: ({ value }) => {
return h("div", null, value as string);
},
},
];
const fileToDataURL = (file: File | Blob): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e: ProgressEvent<FileReader>) => {
const data = (e.target as any).result;
resolve(data);
};
reader.onerror = e => {
// 读取文件失败
reject(new Error(e as any));
};
reader.readAsDataURL(file);
});
};
</script>
<template>
<ProForm v-model="state" :columns="columns" :label-width="200" />
{{ state }}
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
隐藏源代码
自定义表单组件(jsx/tsx)
除了 h 函数,你还可以使用 jsx 或 tsx 自定义单元格渲染。
警告
使用 jsx 或 tsx 时,请在 script 上将 lang=ts 改为 lang=tsx。
html
<script setup lang="tsx">1
vue
<script lang="tsx" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref } from "vue";
import { ElInput } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
width: 120,
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
render: ({ value }) => {
return <div style="color: green;">{value}</div>;
},
},
{
label: "状态",
width: 120,
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
render: ({ value }) => {
return <ElInput modelValue={value as string} />;
},
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns="columns" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
隐藏源代码
自定义表单组件 (插槽)
Teek 会将单个 column 的 prop 属性生成插槽,因此你也可以使用插槽自定义表单组件渲染。
生成插槽的规则为当前 prop 的值,假设一个 column 的 prop 为 username,那么插槽为 username。
vue
<script lang="ts" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref } from "vue";
import { ElInput } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
width: 120,
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
},
{
label: "状态",
width: 120,
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns>
<template #name>
<el-input v-model="state.name" placeholder="自定义输入框插槽" />
</template>
<template #status>
<el-input v-model="state.status" placeholder="自定义输入框插槽" />
</template>
</ProForm>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
隐藏源代码
自定义表单标签 (render)
vue
<script lang="ts" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref, h } from "vue";
import { ElButton } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
renderLabel: ({ value }) => {
return h("div", {}, value as string);
},
},
{
label: "自定义label",
prop: "customName",
renderLabel: () => {
return "label";
},
},
{
label: "状态",
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
renderLabel: ({ value }) => h(ElButton, null, () => value as string),
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns="columns" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
隐藏源代码
自定义表单标签(jsx/tsx)
vue
<script lang="tsx" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref } from "vue";
import { ElButton } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
renderLabel: ({ label }) => {
return <div style="color: green;">{label}</div>;
},
},
{
label: "状态",
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
renderLabel: ({ label }) => {
return <ElButton>{label}</ElButton>;
},
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns="columns" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
隐藏源代码
自定义表单标签 (插槽)
Teek 会将单个 column 的 prop 属性根据规则生成标签 插槽,因此你也可以使用标签 插槽自定义表单标签 渲染。
生成插槽的规则为当前 prop 的值 + -label,假设一个 column 的 prop 为 username,那么表头插槽为 username-label。
vue
<script lang="ts" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref } from "vue";
import { ElInput } from "element-plus";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
width: 120,
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
},
{
label: "状态",
width: 120,
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns>
<template #name>
<el-input v-model="state.name" placeholder="自定义输入框插槽" />
</template>
<template #status>
<el-input v-model="state.status" placeholder="自定义输入框插槽" />
</template>
</ProForm>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
隐藏源代码
自定义表单标签 (renderLabelHTML)
如果你只想对内容进行替换,可以使用 renderLabelHTML 属性返回一个可信的 HTML 字符串进行表头内容渲染。
vue
<script lang="tsx" setup>
import type { ElFormProps, FormColumn } from "@/components/pro/form";
import { ref } from "vue";
import { ProForm } from "@/components/pro/form";
const state = ref({
status: "0",
name: "默认值",
});
const elFormProps: Partial<ElFormProps> = {
rules: {
name: [{ required: true, message: "请输入名称" }],
},
};
const columns: FormColumn[] = [
{
label: "名称",
prop: "name",
valueType: "copy",
tooltip: "名称最多显示6个字符",
renderLabelHTML: ({ label }) => `<span style="color: red">${label}</span>`,
},
{
label: "状态",
prop: "status",
valueType: "select",
options: [
{ label: "未解决", value: "0" },
{ label: "已解决", value: "1" },
{ label: "解决中", value: "2" },
{ label: "失败", value: "3" },
],
renderLabelHTML: ({ label }) => `<span style="color: blue">${label}</span>`,
},
];
</script>
<template>
<ProForm v-model="state" :el-form-props :columns="columns" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
隐藏源代码