本文介绍 Piying-View 支持的 Valibot 复杂 Schema 类型及其对应的视图表现。每个示例的定义都会渲染出一个可交互的表单。
complex-schema-overview.definition.ts
import * as v from 'valibot';
import { actions } from '@piying/view-angular-core';
export const schema = v.object({
name: v.pipe(v.string(), actions.attributes.set({ placeholder: '姓名' })),
user: v.object({
nickname: v.pipe(v.string(), actions.attributes.set({ placeholder: '昵称' })),
age: v.pipe(v.number(), actions.attributes.set({ placeholder: '年龄' })),
active: v.boolean(),
}),
});
export const model = {
name: '张三',
user: { nickname: '小张', age: 20, active: true },
};
使用 v.object() 嵌套定义对象结构,Piying-View 会自动将 object 类型映射到 Group 组件,递归渲染子字段:
complex-nesting.definition.ts
import * as v from 'valibot';
export const schema = v.object({
user: v.object({
name: v.string(),
address: v.object({
city: v.string(),
street: v.string(),
}),
}),
});
export const model = {
user: { name: '张三', address: { city: '北京', street: '长安街' } },
};
在 fieldGlobalConfig.types 中确保 object 有对应的容器组件:
options = {
fieldGlobalConfig: {
types: {
object: { type: PiyingViewGroup }, // Group 容器处理嵌套
},
},
};
使用 v.array() 定义列表型字段,Piying-View 将 array 映射为 FieldArray,使用数组容器组件渲染:
complex-array.definition.ts
import * as v from 'valibot';
export const schema = v.object({
tags: v.array(v.string()),
scores: v.array(v.number()),
});
export const model = { tags: ['v1', 'v2'], scores: [1, 2] };
确保注册了 array 类型:
options = {
fieldGlobalConfig: {
types: {
array: { type: PiyingViewGroup }, // Array 容器处理列表
},
},
};
使用 v.tuple() 定义固定长度和类型的数组,Piying-View 将 tuple 映射为 FieldArray,每个位置对应一个子字段:
complex-tuple.definition.ts
import * as v from 'valibot';
export const schema = v.object({
position: v.tuple([v.number(), v.number()]),
});
export const model = { position: [1, 2] };
使用 v.record() 定义动态键值对,Piying-View 将 record 映射为特殊的 Group,键由用户动态添加:
complex-record.definition.ts
import * as v from 'valibot';
export const schema = v.object({
metadata: v.record(v.string(), v.string()),
scores: v.record(v.string(), v.number()),
});
export const model = { metadata: { k1: 'v1' }, scores: { s1: 1 } };
详见 Record Schema 动态对象组。
使用 v.intersect() 合并多个 object,Piying-View 将 intersect 转换为 FieldLogicGroup,所有子字段平铺到同一层级:
complex-intersect.definition.ts
import * as v from 'valibot';
export const schema = v.intersect([
v.object({ name: v.string() }),
v.object({ age: v.number() }),
]);
export const model = { name: '张三', age: 25 };
通过 layout 可以调整 intersect 中字段的顺序和位置:
import { layout } from '@piying/view-angular-core';
const schema = v.intersect([v.pipe(v.object({ name: v.string() }), layout({ priority: 1 })), v.pipe(v.object({ age: v.number() }), layout({ priority: 2 }))]);
使用 v.union() 定义多个可选类型,Piying-View 将 union 也转换为 FieldLogicGroup,用户可以在不同分支间切换:
complex-union.definition.ts
import * as v from 'valibot';
export const schema = v.object({
value: v.union([v.string(), v.number()]),
});
export const model = { value: 'v1' };
complex-combined.definition.ts
import * as v from 'valibot';
import { formConfig, layout } from '@piying/view-angular-core';
export const schema = v.object({
name: v.string(),
address: v.object({
city: v.string(),
details: v.object({
street: v.string(),
zipCode: v.string(),
}),
}),
positions: v.array(v.tuple([v.number(), v.number()])),
metadata: v.record(v.string(), v.string()),
profile: v.intersect([
v.pipe(v.object({ bio: v.string() }), layout({ priority: 1 })),
v.pipe(v.object({ website: v.string() }), layout({ priority: 2 })),
]),
identifier: v.union([v.string(), v.number()]),
});
export const model = {
name: '',
address: { city: '', details: { street: '', zipCode: '' } },
positions: [[1, 2]],
metadata: {},
profile: { bio: '', website: '' },
identifier: 'x',
};
| Valibot Schema |
FieldControl 类 |
视图表现 |
v.string() / v.number() / v.boolean() |
FieldControl |
单个输入控件 |
v.object() |
FieldGroup |
对象容器(渲染子字段列表) |
v.array() |
FieldArray |
数组容器(可增删项) |
v.tuple() |
FieldArray |
固定长度数组 |
v.record() |
FieldGroup |
动态键值对容器 |
v.intersect() |
FieldLogicGroup |
逻辑分组(字段合并) |
v.union() |
FieldLogicGroup |
逻辑分组(分支切换) |