表单校验

Form + FormGroup + Validator 的字段校验、异步远程校验与错误呈现。

最后更新

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。

相关

  • 表格里的行内编辑复用同一套校验器,见表格分页 §行内编辑。
  • Result 契约细节见数据层。
微信公众号二维码 扫码关注公众号
QQ 交流群二维码 扫码加入 QQ 群