Known 的表单层围绕 <Form> + <FormGroup> + 校验器三层展开。字段级、表单级、异步校验都覆盖。
最小可用
<Form Model="@order" OnSubmit="@SubmitAsync">
<FormGroup Field="@nameof(Order.Customer)" Label="客户" Required="true" />
<FormGroup Field="@nameof(Order.Amount)" Label="金额" Type="number" Min="0.01" />
<FormGroup Field="@nameof(Order.Status)" Label="状态" Type="select"
Options="@EnumHelper.ToOptions<OrderStatus>()" />
<Button Kind="primary" Type="submit" Text="保存" />
</Form>
Required / Min / Max / Pattern / MaxLength / Email 是内置校验器,直接参数化。
自定义校验器
<FormGroup Field="@nameof(Order.Customer)"
Label="客户"
Validator="@RequireCustomerNoX" />
@code {
private string? RequireCustomerNoX(object? value)
{
var s = value as string;
if (string.IsNullOrWhiteSpace(s)) return "客户名不能为空";
if (s.Contains('X')) return "客户名不允许包含 X";
return null; // null = 通过
}
}
返回值 null 通过、非 null 是给用户看的错误文案。
异步校验(远程唯一性)
<FormGroup Field="@nameof(Order.Customer)"
Label="客户"
AsyncValidator="@CheckCustomerExistsAsync" />
@code {
[Inject] IOrderService Orders { get; set; } = default!;
private async Task<string?> CheckCustomerNoDupAsync(object? value)
{
var name = value as string;
if (string.IsNullOrWhiteSpace(name)) return null;
var exists = await Orders.ExistsByNameAsync(name); // 服务内部走 db.ExistsAsync<Order>(...)
return exists ? "客户已存在" : null;
}
}
表单内部自动 debounce 300ms、显示 loading 圈,OnSubmit 期间 Form.IsValid 反映异步结果。
错误呈现
- 字段级:
FormGroup下方一行红字(--no-fg色),同时输入框描边变红。 - 表单级:
<Form ShowSummary="true">会在提交失败时上方汇总一条<Alert Type="error">。 - Toast:
UIService.Error("...")由Container全局弹,适合服务端返 400 时兜底。
三者不互斥,但同一错误只走一路——字段级错误不要再 Toast 一遍,会吵。
与服务端契约对齐
[WebApi] 接口返回 Result 时,Result.Message 建议直接对应到"哪个字段错":
public Result Save(Order o)
{
if (string.IsNullOrWhiteSpace(o.Customer))
return Result.Fail("Customer 不能为空", field: "Customer");
// ...
}
field 字段(Batch 2 会补上)由 Form 消费,把服务端错误也映射回具体输入框。
当前先用 Alert 汇总,服务端返 field 前不做强绑定。
常见坑
Model属性用了record—record不可变,@bind无法写回;改class或用Value/ValueChanged。Validator里同步调异步 — 用AsyncValidator,不要写async void。- 表单嵌表单 —
Form之间不能嵌套;跨表单提交用外层按钮 +EditContext广播。 - 异步校验每次 keystroke 都打网络 —
Form已内置 300ms debounce;如果你重写了Validator手动触发,请自己加 debounce。
扫码关注公众号
扫码加入 QQ 群