简介
Form-Render 是一个基于 JSON Schema 的动态表单渲染器,支持通过配置化的方式快速生成复杂的表单界面。它提供了丰富的表单组件、灵活的布局系统和强大的验证机制,让开发者能够以声明式的方式构建表单。
核心特性
- JSON Schema 驱动:基于标准的 JSON Schema 规范,支持复杂的数据结构
- 丰富的组件库:内置多种表单组件,支持自定义组件扩展
- 灵活的布局:支持多种布局方式,响应式设计
- 强大的验证:内置验证规则,支持自定义验证逻辑
- 主题定制:支持主题切换和样式定制
- TypeScript 支持:完整的类型定义,提供良好的开发体验
安装
npm install form-render
# 或
yarn add form-render
# 或
pnpm add form-render基本用法
简单示例
import FormRender, { useForm } from "form-render";
const BasicExample = () => {
  const form = useForm();
  const schema = {
    type: "object",
    properties: {
      name: {
        title: "姓名",
        type: "string",
        required: true,
        placeholder: "请输入姓名",
      },
      age: {
        title: "年龄",
        type: "number",
        minimum: 0,
        maximum: 120,
      },
      email: {
        title: "邮箱",
        type: "string",
        format: "email",
        required: true,
      },
    },
  };
  const handleSubmit = (data) => {
    console.log("表单数据:", data);
    alert("表单提交成功!\n" + JSON.stringify(data, null, 2));
  };
  const handleReset = () => {
    form.resetFields();
  };
  const handleValidate = async () => {
    try {
      const valid = await form.validateFields();
      console.log("验证结果:", valid);
    } catch (error) {
      console.log("验证失败:", error);
    }
  };
  const getCurrentFormData = () => {
    return form.getFieldsValue();
  };
  return (
    <div className="max-w-2xl mx-auto p-6">
      <h1 className="text-2xl font-bold mb-6 text-center text-blue-600">
        FormRender 示例
      </h1>
      <div className="bg-white rounded-lg shadow-lg p-6">
        <FormRender
          form={form}
          schema={schema}
          onFinish={handleSubmit}
          displayType="row"
          labelWidth={120}
        />
        <div className="mt-6 flex gap-4 justify-center">
          <button
            onClick={handleReset}
            className="bg-gray-500 hover:bg-gray-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            重置表单
          </button>
          <button
            onClick={handleValidate}
            className="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            验证表单
          </button>
          <button
            onClick={() => form.submit()}
            className="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            提交表单
          </button>
        </div>
      </div>
    </div>
  );
};
export default BasicExample;
复杂表单示例
import FormRender, { useForm } from "form-render";
const ComplexExample = () => {
  const form = useForm();
  const schema = {
    type: "object",
    properties: {
      // 基础输入
      name: {
        title: "姓名",
        type: "string",
        required: true,
        placeholder: "请输入姓名",
      },
      email: {
        title: "邮箱",
        type: "string",
        format: "email",
        required: true,
        placeholder: "请输入邮箱地址",
      },
      // 选择类组件
      gender: {
        title: "性别",
        type: "string",
        enum: ["male", "female", "other"],
        enumNames: ["男", "女", "其他"],
        widget: "radio",
        required: true,
      },
      city: {
        title: "所在城市",
        type: "string",
        enum: ["beijing", "shanghai", "guangzhou", "shenzhen"],
        enumNames: ["北京", "上海", "广州", "深圳"],
        widget: "select",
        placeholder: "请选择城市",
      },
      hobbies: {
        title: "兴趣爱好",
        type: "array",
        items: {
          type: "string",
        },
        enum: ["reading", "music", "sports", "travel"],
        enumNames: ["阅读", "音乐", "运动", "旅行"],
        widget: "checkboxes",
      },
      // 日期选择
      birthday: {
        title: "出生日期",
        type: "string",
        format: "date",
        widget: "datePicker",
      },
      // 文本域
      bio: {
        title: "个人简介",
        type: "string",
        widget: "textarea",
        placeholder: "请简单介绍一下自己...",
        maxLength: 500,
      },
      // 开关
      newsletter: {
        title: "订阅邮件通知",
        type: "boolean",
        widget: "switch",
        default: false,
      },
    },
  };
  const handleSubmit = (data) => {
    console.log("表单数据:", data);
    alert("表单提交成功!\n" + JSON.stringify(data, null, 2));
  };
  const handleReset = () => {
    form.resetFields();
  };
  const handleValidate = async () => {
    try {
      const valid = await form.validateFields();
      console.log("验证结果:", valid);
    } catch (error) {
      console.log("验证失败:", error);
    }
  };
  const getCurrentFormData = () => {
    return form.getFieldsValue();
  };
  return (
    <div className="max-w-2xl mx-auto p-6">
      <h1 className="text-2xl font-bold mb-6 text-center text-blue-600">
        FormRender 表单示例
      </h1>
      <p className="text-gray-600 text-center mb-6">
        包含8种常用表单组件:文本输入、邮箱、单选框、下拉选择、多选框、日期选择、文本域、开关
      </p>
      <div className="bg-white rounded-lg shadow-lg p-6">
        <FormRender
          form={form}
          schema={schema}
          onFinish={handleSubmit}
          displayType="row"
          labelWidth={120}
        />
        <div className="mt-6 flex flex-wrap gap-4 justify-center">
          <button
            onClick={handleReset}
            className="bg-gray-500 hover:bg-gray-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            重置表单
          </button>
          <button
            onClick={handleValidate}
            className="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            验证表单
          </button>
          <button
            onClick={() => {
              const data = getCurrentFormData();
              console.log("当前表单数据:", data);
              alert("当前表单数据:\n" + JSON.stringify(data, null, 2));
            }}
            className="bg-yellow-500 hover:bg-yellow-600 text-white px-6 py-2 rounded-lg transition-colors duration-200"
          >
            提交表单
          </button>
        </div>
      </div>
    </div>
  );
};
export default ComplexExample;
API 参考
FormRender Props
| 属性名 | 类型 | 默认值 | 描述 | 
|---|---|---|---|
| form | object | – | 表单实例,通过 useForm() 创建 | 
| schema | object | – | JSON Schema 配置对象 | 
| onFinish | function | – | 表单提交成功回调函数 | 
| onFinishFailed | function | – | 表单提交失败回调函数 | 
| displayType | string | ‘column’ | 布局方式:’column’ | ‘row’ | ‘inline’ | 
| labelWidth | number | 110 | 标签宽度(像素) | 
| maxWidth | number | – | 表单最大宽度 | 
| widgets | object | {} | 自定义组件映射 | 
| mapping | object | {} | 字段映射配置 | 
| readonly | boolean | false | 是否只读模式 | 
| disabled | boolean | false | 是否禁用表单 | 
useForm Hook
useForm 是 form-render 提供的表单管理 Hook,用于创建表单实例。
const form = useForm();表单实例方法
| 方法名 | 参数 | 返回值 | 描述 | 
|---|---|---|---|
| getFieldsValue | (nameList?: string[]) | object | 获取表单字段值 | 
| getFieldValue | (name: string) | any | 获取单个字段值 | 
| setFieldsValue | (values: object) | void | 设置表单字段值 | 
| setFieldValue | (name: string, value: any) | void | 设置单个字段值 | 
| resetFields | (nameList?: string[]) | void | 重置表单字段 | 
| validateFields | (nameList?: string[]) | Promise | 验证表单字段 | 
| submit | () | void | 提交表单 | 
| scrollToField | (name: string) | void | 滚动到指定字段 | 
使用示例
const form = useForm();
// 获取所有字段值
const allValues = form.getFieldsValue();
// 获取单个字段值
const name = form.getFieldValue("name");
// 设置字段值
form.setFieldsValue({ name: "张三", age: 25 });
// 重置表单
form.resetFields();
// 验证表单
form
  .validateFields()
  .then((values) => {
    console.log("验证通过:", values);
  })
  .catch((errors) => {
    console.log("验证失败:", errors);
  });
// 提交表单
form.submit();Schema 配置
基础字段类型
// 字符串类型
{
  type: 'string',
  title: '标题',
  placeholder: '占位符',
  maxLength: 100,
  minLength: 1,
  pattern: '^[a-zA-Z]+$', // 正则验证
  format: 'email', // 格式验证: 'email' | 'url' | 'date' | 'time'
  required: true // 必填字段
}
// 数字类型
{
  type: 'number',
  title: '数字',
  minimum: 0,
  maximum: 100,
  multipleOf: 5, // 倍数验证
  required: true
}
// 布尔类型
{
  type: 'boolean',
  title: '开关',
  widget: 'switch', // 'switch' | 'checkbox'
  default: false
}
// 数组类型(多选)
{
  type: 'array',
  title: '多选列表',
  items: {
    type: 'string'
  },
  enum: ['option1', 'option2', 'option3'],
  enumNames: ['选项1', '选项2', '选项3'],
  widget: 'checkboxes',
  minItems: 1,
  maxItems: 10
}
// 对象类型
{
  type: 'object',
  title: '对象',
  properties: {
    // 子字段定义
  }
}常用 Widget 类型
// 输入框
{ type: 'string', widget: 'input' }
// 文本域
{ type: 'string', widget: 'textarea' }
// 密码框
{ type: 'string', widget: 'password' }
// 下拉选择
{
  type: 'string',
  widget: 'select',
  enum: ['value1', 'value2'],
  enumNames: ['显示名1', '显示名2']
}
// 单选框
{
  type: 'string',
  widget: 'radio',
  enum: ['male', 'female'],
  enumNames: ['男', '女']
}
// 多选框
{
  type: 'array',
  widget: 'checkboxes',
  items: { type: 'string' },
  enum: ['reading', 'music'],
  enumNames: ['阅读', '音乐']
}
// 日期选择器
{ type: 'string', format: 'date', widget: 'datePicker' }
// 开关
{ type: 'boolean', widget: 'switch' }验证规则
内置验证
{
  type: 'string',
  required: true,           // 必填
  minLength: 2,            // 最小长度
  maxLength: 50,           // 最大长度
  pattern: '^[a-zA-Z]+$',  // 正则表达式
  format: 'email'          // 格式验证
}自定义验证
import FormRender, { useForm } from "form-render";
const ValidationExample = () => {
  const form = useForm();
  const schema = {
    type: "object",
    properties: {
      password: {
        title: "密码",
        type: "string",
        widget: "password",
        required: true,
        minLength: 6,
      },
      confirmPassword: {
        title: "确认密码",
        type: "string",
        widget: "password",
        required: true,
      },
    },
  };
  // 自定义验证函数
  const validateForm = (formData) => {
    const errors = {};
    if (formData.password !== formData.confirmPassword) {
      errors.confirmPassword = "两次密码输入不一致";
    }
    if (formData.password && formData.password.length < 6) {
      errors.password = "密码长度不能少于6位";
    }
    return errors;
  };
  const handleFinish = (data) => {
    const errors = validateForm(data);
    if (Object.keys(errors).length > 0) {
      console.log("验证失败:", errors);
      // 可以设置字段错误状态
      return;
    }
    console.log("验证通过,提交数据:", data);
  };
  return <FormRender form={form} schema={schema} onFinish={handleFinish} />;
};最佳实践
- 合理使用 Schema 结构:将复杂表单拆分为多个对象层级
- 组件复用:抽取通用的 Schema 配置
- 性能优化:大表单使用分步骤渲染
- 用户体验:提供清晰的验证提示和加载状态
- 类型安全:使用 TypeScript 定义 Schema 类型
常见问题
Q: 如何实现字段联动?
A: 可以通过监听表单值变化来实现字段联动:
const form = useForm();
const [formData, setFormData] = useState({});
// 监听字段变化
const handleValuesChange = (changedValues, allValues) => {
  setFormData(allValues);
  // 当国家改变时,清空城市选择
  if (changedValues.country) {
    form.setFieldValue("city", undefined);
  }
};
<FormRender form={form} schema={schema} onValuesChange={handleValuesChange} />;Q: 如何获取和设置表单数据?
A: 使用 form 实例的方法:
const form = useForm();
// 获取所有字段值
const allValues = form.getFieldsValue();
// 获取单个字段值
const name = form.getFieldValue("name");
// 设置字段值
form.setFieldsValue({ name: "张三", age: 25 });
// 设置单个字段值
form.setFieldValue("name", "李四");Q: 如何自定义表单验证?
A: 在 schema 中定义验证规则,或在 onFinish 中进行自定义验证:
// Schema 中定义
{
  type: 'string',
  required: true,
  minLength: 6,
  pattern: '^[a-zA-Z0-9]+$'
}
// 自定义验证逻辑
const handleFinish = (data) => {
  if (data.password !== data.confirmPassword) {
    // 处理验证失败
    return;
  }
  // 验证通过,提交数据
};Q: 如何处理文件上传?
A: 使用内置的 upload 组件或自定义上传组件:
{
  title: '头像',
  type: 'string',
  widget: 'upload',
  action: '/api/upload',
  accept: 'image/*'
}Q: 如何实现动态表单?
A: 根据条件动态修改 schema:
const [schema, setSchema] = useState(baseSchema);
useEffect(() => {
  if (formData.type === "personal") {
    setSchema(personalSchema);
  } else {
    setSchema(companySchema);
  }
}, [formData.type]);Q: 表单性能优化有哪些方法?
A:
- 使用 React.memo包装自定义组件
- 避免在 render 中创建新的 schema 对象
- 大表单考虑分页或分步骤渲染
- 合理使用 shouldUpdate控制组件更新
 原文链接:https://code.ifrontend.net/archives/904,转载请注明出处。		    			
		             
	
评论0