Skip to content

Form 表单

介绍

表单组件,用于数据收集和校验,支持多种校验规则、自定义校验函数,以及标签布局配置。由 TnFormTnFormItem 组合使用。

引入

typescript
import { TnForm, TnFormItem, TnFormController } from "@tuniao/tn-ui";

类型说明

TnFormController -- 表单控制器

方法说明参数返回值
validate校验全部字段callBack?: (valid: boolean, fields: TnFieldValidateInfo[]) => voidPromise<TnFormValidateResult>
validateField校验指定字段name: string, callBack?: (valid: boolean, field?: TnFieldValidateInfo) => voidPromise<TnFieldValidateResult>
resetValidation重置校验状态name?: string | string[]void
getFormValues获取所有表单值-Record<string, TnFieldValueType>
setFormValues批量设置表单值values: Record<string, TnFieldValueType>void

TnFormValidateResult -- 校验结果

typescript
interface TnFormValidateResult {
  valid: boolean;
  fields: TnFieldValidateInfo[];
}

TnFieldValidateResult -- 单字段校验结果

typescript
interface TnFieldValidateResult {
  valid: boolean;
  field: TnFieldValidateInfo;
}

TnFieldValidateInfo -- 校验信息

typescript
interface TnFieldValidateInfo {
  label: string;
  name: string;
  message: string;
}

TnFieldValueType -- 表单字段值类型

typescript
type TnFieldValueType = string | number | boolean | Array<string | number> | Array<Resource>;

TnFormRuleItem -- 校验规则

属性说明类型
required是否必填boolean
message校验失败提示信息ResourceStr
pattern正则校验RegExp
validator自定义校验函数(value: string) => boolean | string | Promise<boolean | string>
trigger触发方式"blur" | "change"
min最小长度/值number
max最大长度/值number

代码演示

基础用法

TnForm 作为容器,内部放置 TnFormItem。每个 TnFormItem 通过 prop 绑定字段名,label 设置标签。

基础用法

点我查看代码
typescript
@ObservedV2
export default class TnFormViewModel {
  /** 表单数据 */
  @Trace basicForm: BasicFormData = new BasicFormData();
  /** 表单控制器 */
  @Trace basicController: TnFormController = new TnFormController();
  /** 表单 ID */
  readonly basicFormId: string = "basicForm";
  /** 表单校验规则 */
  basicRules: TnFormRules = {
    "name": [
      { required: true, message: "请输入姓名" },
      { min: 2, max: 10, message: "姓名长度在2-10个字符之间" }
    ],
    "phone": [
      { required: true, message: "请输入手机号" }
    ]
  };

  /**
   * 提交表单
   */
  submitBasicForm(): void {
    this.basicController.validate().then((res): void => {
      if (res.valid) {
        this.validateResultMsg = "验证通过";
      } else {
        const labels: Array<string> = res.fields.map((item): string => item.label);
        this.validateResultMsg = `${labels.join(",")} 验证失败`;
      }
    });
  }
}

@Local  vm: TnFormViewModel = new TnFormViewModel();

@Builder
private BasicFormSection(): void {
  TnList({ title: "基础用法", description: "支持验证单个字段、设置表单值、提交验证", card: true }) {
    TnForm({
      formId: this.vm.basicFormId,
      rules: this.vm.basicRules,
      controller: this.vm.basicController
    }) {
      TnListItem({ bottomBorder: true }) {
        TnFormItem({
          formId: this.vm.basicFormId,
          prop: "name",
          label: "姓名",
          value: this.vm.basicForm.name,
          rules: [
            { required: true, message: "请输入姓名" },
            { min: 2, max: 10, message: "姓名长度在2-10个字符之间" }
          ]
        }) {
          TnInput({
            modelValue: this.vm.basicForm.name,
            placeholder: "请输入姓名",
            onInput: (value: string): void => {
              this.vm.setBasicName(value);
            }
          });
        };
      }

      TnListItem() {
        TnFormItem({
          formId: this.vm.basicFormId,
          prop: "phone",
          label: "手机号",
          value: this.vm.basicForm.phone,
          rules: [
            { required: true, message: "请输入手机号" }
          ]
        }) {
          TnInput({
            modelValue: this.vm.basicForm.phone,
            type: "number",
            placeholder: "请输入手机号",
            onInput: (value: string): void => {
              this.vm.setBasicPhone(value);
            }
          });
        };
      }
    };

    SpaceVerticalMedium();

    // 操作按钮
    Column({ space: SPACE.XSM }) {
      Row({ space: SPACE.XSM }) {
        TnButton({
          content: "提交",
          type: "primary",
          btnSize: "sm",
          onBtnClick: (): void => {
            this.vm.submitBasicForm();
          }
        });
      }
      .width(P100)
        .justifyContent(FlexAlign.SpaceEvenly);
    }
    .width(P100)
      .padding({ left: SPACE.NORMAL, right: SPACE.NORMAL, bottom: SPACE.SM });
  }
}

表单校验

通过 TnFormController 触发校验,TnFormItemrules 属性设置校验规则,required 属性显示必填标识。

表单校验

点我查看代码
typescript
@Local formController: TnFormController = new TnFormController();
@Local formData: Record<string, Object> = {
  username: "" as Object,
  phone: "" as Object,
};

Column() {
  TnForm({ controller: this.formController }) {
    TnFormItem({
      prop: "username",
      label: "用户名",
      required: true,
      rules: [
        { required: true, message: "请输入用户名" },
        { min: 2, max: 10, message: "用户名长度为 2-10 个字符" },
      ],
    }) {
      TextInput({ placeholder: "请输入用户名" })
        .onChange((value: string) => {
          this.formData["username"] = value as Object;
        })
    }
    TnFormItem({
      prop: "phone",
      label: "手机号",
      required: true,
      rules: [
        { required: true, message: "请输入手机号" },
        { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
      ],
    }) {
      TextInput({ placeholder: "请输入手机号" })
        .onChange((value: string) => {
          this.formData["phone"] = value as Object;
        })
    }
  }

  TnButton({
    content: "提交",
    type: "primary",
    onBtnClick: async () => {
      const valid: boolean = await this.formController.validate();
      if (valid) {
        // 校验通过,提交表单
      }
    },
  })
}

自定义校验规则

通过 validator 属性传入自定义校验函数,支持异步校验。

自定义校验规则

点我查看代码
typescript
@ObservedV2
export default class TnFormViewModel {
  /** 自定义校验表单数据 */
  @Trace customRuleForm: CustomRuleFormData = new CustomRuleFormData();
  /** 自定义校验表单控制器 */
  @Trace customRuleController: TnFormController = new TnFormController();
  /** 自定义校验表单 ID */
  readonly customRuleFormId: string = "customRuleForm";
  /** 正则校验模式 */
  private patternReg: RegExp = /\d{6}/;
  /** 函数校验器 */
  private funcValidator: (value: string) => boolean = (val: string): boolean => /1\d{10}/.test(val);
  /** 函数校验器(返回消息) */
  private funcMsgValidator: (value: string) => string = (val: string): string => {
    if (val.length === 0) {
      return "请输入内容";
    }
    if (!/^\d+$/.test(val)) {
      return `${val} 不合法,请输入纯数字`;
    }
    return "";
  };
  /** 异步校验器 */
  private asyncValidator: (value: string) => Promise<boolean> = (val: string): Promise<boolean> => {
    return new Promise<boolean>((resolve: (value: boolean) => void): void => {
      setTimeout((): void => {
        resolve(val === "1234");
      }, 1000);
    });
  };
  /** 自定义校验规则 */
  customRuleRules: TnFormRules = {
    "patternValue": [
      { pattern: this.patternReg, message: "请输入6位数字" } as TnFormRuleItem
    ],
    "funcValue": [
      { validator: this.funcValidator, message: "请输入正确的手机号" } as TnFormRuleItem
    ],
    "funcMsgValue": [
      { validator: this.funcMsgValidator } as TnFormRuleItem
    ],
    "asyncValue": [
      { validator: this.asyncValidator, message: "请输入正确内容(1234)" } as TnFormRuleItem
    ]
  };
  /**
   * 设置正则校验值
   * @param value 输入值
   */
  setPatternValue(value: string): void {
    this.customRuleForm.patternValue = value;
  }

  /**
   * 设置函数校验值
   * @param value 输入值
   */
  setFuncValue(value: string): void {
    this.customRuleForm.funcValue = value;
  }

  /**
   * 设置函数消息校验值
   * @param value 输入值
   */
  setFuncMsgValue(value: string): void {
    this.customRuleForm.funcMsgValue = value;
  }

  /**
   * 设置异步校验值
   * @param value 输入值
   */
  setAsyncValue(value: string): void {
    this.customRuleForm.asyncValue = value;
  }

  /**
   * 提交自定义校验表单
   */
  submitCustomRuleForm(): void {
    this.customRuleController.validate().then((res): void => {
      if (res.valid) {
        this.validateResultMsg = "自定义校验全部通过";
      } else {
        const labels: Array<string> = res.fields.map((item): string => item.message);
        this.validateResultMsg = labels.join("; ");
      }
    });
  }
}

@Local  vm: TnFormViewModel = new TnFormViewModel();

@Builder
private CustomRuleFormSection(): void {
  TnList({ title: "自定义校验规则", description: "支持正则、函数、异步等多种校验方式", card: true }) {
    TnForm({
      formId: this.vm.customRuleFormId,
      rules: this.vm.customRuleRules,
      controller: this.vm.customRuleController
    }) {
      TnListItem({ bottomBorder: true }) {
        TnFormItem({
          formId: this.vm.customRuleFormId,
          prop: "patternValue",
          label: "正则校验",
          value: this.vm.customRuleForm.patternValue
        }) {
          TnInput({
            modelValue: this.vm.customRuleForm.patternValue,
            placeholder: "请输入6位数字",
            onInput: (value: string): void => {
              this.vm.setPatternValue(value);
            }
          });
        };
      }

      TnListItem({ bottomBorder: true }) {
        TnFormItem({
          formId: this.vm.customRuleFormId,
          prop: "funcValue",
          label: "函数校验",
          value: this.vm.customRuleForm.funcValue
        }) {
          TnInput({
            modelValue: this.vm.customRuleForm.funcValue,
            placeholder: "返回 true/false",
            onInput: (value: string): void => {
              this.vm.setFuncValue(value);
            }
          });
        };
      }

      TnListItem({ bottomBorder: true }) {
        TnFormItem({
          formId: this.vm.customRuleFormId,
          prop: "funcMsgValue",
          label: "返回消息",
          value: this.vm.customRuleForm.funcMsgValue
        }) {
          TnInput({
            modelValue: this.vm.customRuleForm.funcMsgValue,
            placeholder: "返回验证信息",
            onInput: (value: string): void => {
              this.vm.setFuncMsgValue(value);
            }
          });
        };
      }

      TnListItem() {
        TnFormItem({
          formId: this.vm.customRuleFormId,
          prop: "asyncValue",
          label: "异步校验",
          value: this.vm.customRuleForm.asyncValue
        }) {
          TnInput({
            modelValue: this.vm.customRuleForm.asyncValue,
            placeholder: "异步校验(输入1234通过)",
            onInput: (value: string): void => {
              this.vm.setAsyncValue(value);
            }
          });
        };
      }
    };

    SpaceVerticalMedium();

    Row() {
      TnButton({
        content: "提交",
        type: "primary",
        btnSize: "sm",
        onBtnClick: (): void => {
          this.vm.submitCustomRuleForm();
        }
      });
    }
    .width(P100)
      .justifyContent(FlexAlign.Center)
      .padding({ bottom: SPACE.SM });
  }
}

标签位置

通过 TnFormItemlabelPosition 属性设置标签位置,支持 left(左侧)和 top(顶部)。

点我查看代码
typescript
Column() {
  TnForm() {
    TnFormItem({
      prop: "username",
      label: "用户名",
      labelPosition: "left",
      labelWidth: 80,
    }) {
      TextInput({ placeholder: "标签在左侧" })
    }
    TnFormItem({
      prop: "bio",
      label: "个人简介",
      labelPosition: "top",
    }) {
      TextArea({ placeholder: "标签在顶部" })
    }
  }
}

重置校验

通过 TnFormControllerresetValidation 方法重置校验状态。不传参数时重置全部字段,传入字段名或字段名数组时仅重置指定字段。

点我查看代码
typescript
@Local formController: TnFormController = new TnFormController();
@Local formData: Record<string, Object> = {
  username: "" as Object,
  phone: "" as Object,
};

Column() {
  TnForm({ controller: this.formController }) {
    TnFormItem({
      prop: "username",
      label: "用户名",
      required: true,
      rules: [{ required: true, message: "请输入用户名" }],
    }) {
      TextInput({ placeholder: "请输入用户名" })
        .onChange((value: string) => {
          this.formData["username"] = value as Object;
        })
    }
    TnFormItem({
      prop: "phone",
      label: "手机号",
      required: true,
      rules: [{ required: true, message: "请输入手机号" }],
    }) {
      TextInput({ placeholder: "请输入手机号" })
        .onChange((value: string) => {
          this.formData["phone"] = value as Object;
        })
    }
  }

  Row({ space: 10 }) {
    TnButton({
      content: "重置全部",
      type: "info",
      onBtnClick: () => {
        this.formController.resetValidation();
      },
    })
    TnButton({
      content: "重置用户名",
      type: "info",
      onBtnClick: () => {
        this.formController.resetValidation("username");
      },
    })
  }
}

API

TnForm Props

参数说明类型默认值
formId表单唯一标识string""
rules验证规则集TnFormRules{}
labelWidth标签宽度,单位 vpnumber80
labelPosition标签位置"left" | "top""left"
colon标签后是否显示冒号booleanfalse
requireAsteriskPosition必填星号位置"left" | "right""left"
showMessage是否显示验证错误消息booleantrue
disabled是否禁用所有字段booleanfalse
space字段间距,单位 vpnumber0
controller表单控制器实例TnFormControllernew TnFormController()

TnForm Slots

名称说明
defaultBuilder默认内容插槽,用于放置 TnFormItem 表单项

TnFormItem Props

参数说明类型默认值
formId表单标识,用于关联 TnFormstring-
prop字段名,对应表单数据的 keystring-
label标签文本ResourceStr-
labelWidth标签宽度,单位 vp,0 表示继承 TnFormnumber0
labelPosition标签位置,不设置时继承 TnForm"left" | "top"-
required是否显示必填标识boolean-
rules校验规则TnFormRuleItem[]-
showMessage是否显示校验错误信息,不设置时继承 TnFormboolean-
value字段值,用于校验TnFieldValueType""

TnFormItem Slots

名称说明
defaultBuilder默认内容插槽,用于放置输入组件

TnFormItem Events

事件名说明回调参数
onValueChange字段值变化时触发(value: TnFieldValueType) => void

TnFormController 方法

方法名说明参数返回值
validate校验全部字段callBack?: (valid: boolean, fields: TnFieldValidateInfo[]) => voidPromise<TnFormValidateResult>
validateField校验指定字段name: string, callBack?: (valid: boolean, field?: TnFieldValidateInfo) => voidPromise<TnFieldValidateResult>
resetValidation重置校验状态name?: string | string[]void
getFormValues获取全部表单值-Record<string, TnFieldValueType>
setFormValues批量设置表单值values: Record<string, TnFieldValueType>void