✅ 背景说明

在企业系统中,表单随处可见,如:

  • 创建 / 编辑表单页

  • 设置参数表单

  • 登录 / 注册表单

如果每个页面都分别处理 字段校验错误提示表单提交,不仅冗余重复,还容易遗漏字段或逻辑不一致。

本篇目标是构建一个通用表单容器组件 FormWrapper,实现:

  • 表单数据集中管理

  • 校验逻辑统一触发

  • 错误信息自动显示

  • 表单项与容器分离、便于插槽化使用


🧱 一、组件目标功能

  • 接收字段定义和校验规则

  • 提供统一的提交方法(回调或 Promise)

  • 自动收集各字段输入值

  • 自动标记错误字段

  • 可嵌套任意输入组件作为插槽内容


📦 二、组件结构设计

interface FormField {
  key: string;
  label: string;
  value: string;
  required?: boolean;
  validator?: (val: string) => string | undefined; // 错误信息返回
}

@Component
struct FormWrapper {
  @Prop fields: FormField[] = [];
  @Prop onSubmit: (data: Record<string, string>) => void = () => {};
  @Slot content?: () => void;
}

🧩 三、表单内部状态管理

@State private formData: Record<string, string> = {};
@State private errors: Record<string, string> = {};

✅ 四、初始化字段值

aboutToAppear() {
  this.formData = {};
  this.errors = {};

  this.fields.forEach(f => {
    this.formData[f.key] = f.value || '';
    this.errors[f.key] = '';
  });
}

🚀 五、表单校验逻辑封装

private validate(): boolean {
  let isValid = true;
  this.errors = {};

  this.fields.forEach(f => {
    const val = this.formData[f.key];
    if (f.required && !val.trim()) {
      this.errors[f.key] = `${f.label}不能为空`;
      isValid = false;
    } else if (f.validator) {
      const msg = f.validator(val);
      if (msg) {
        this.errors[f.key] = msg;
        isValid = false;
      }
    }
  });

  return isValid;
}

🧪 六、组件渲染结构

build() {
  Column({ space: 12 }) {
    this.fields.forEach(f => {
      Column({ space: 4 }) {
        Text(f.label).fontSize(14)
        TextInput({ text: this.formData[f.key] })
          .onChange(v => this.formData[f.key] = v)
          .border({ color: this.errors[f.key] ? '#f44336' : '#ccc', width: 1 })
          .padding(6)

        if (this.errors[f.key]) {
          Text(this.errors[f.key]).fontSize(12).color('#f44336')
        }
      }
    })

    if (this.content) this.content!()

    Button('提交')
      .margin({ top: 16 })
      .onClick(() => {
        if (this.validate()) {
          this.onSubmit(this.formData);
        }
      })
  }
}

🧾 七、父组件使用示例

@Component
struct UserForm {
  private formFields: FormField[] = [
    { key: 'username', label: '用户名', required: true },
    { key: 'email', label: '邮箱', validator: (v) => /\S+@\S+\.\S+/.test(v) ? undefined : '邮箱格式错误' }
  ];

  build() {
    FormWrapper({
      fields: this.formFields,
      onSubmit: (data) => {
        console.info('表单提交成功:', data);
      }
    }) {
      Text('填写完毕后点击提交').fontSize(12).color('#888')
    }
  }
}

⚠️ 八、常见问题与建议

问题 原因 建议
校验不触发 没有调用 validate() 需主动调用或统一在 submit 时验证
错误提示不显示 错误字段未渲染绑定 errors[field.key] 显示对应信息
输入值未提交 状态未同步 onChange 更新 formData 中的值

🚀 九、拓展建议

  • 支持 blur 校验(失焦验证)

  • 支持不同类型字段(select / date / radio)

  • 封装 FormItem 组件用于单个字段输入封装

  • 可联动 DialogBox 使用,作为弹窗表单模块

  • 搭配 FormSchema 实现 JSON 驱动动态表单构建


✅ 小结

本篇封装了一个支持字段定义、统一校验、集中管理、自动收集的 FormWrapper 表单容器组件,是提升企业项目表单一致性与开发效率的重要手段。

下一篇将进入第13篇:

《第13篇:构建动态弹窗 FormDialog(弹窗 + 表单 + 事件回调三合一)》

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐