所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Form-Render:基于JSON Schema的React动态表单开发神器

简介

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

属性名类型默认值描述
formobject表单实例,通过 useForm() 创建
schemaobjectJSON Schema 配置对象
onFinishfunction表单提交成功回调函数
onFinishFailedfunction表单提交失败回调函数
displayTypestring‘column’布局方式:’column’ | ‘row’ | ‘inline’
labelWidthnumber110标签宽度(像素)
maxWidthnumber表单最大宽度
widgetsobject{}自定义组件映射
mappingobject{}字段映射配置
readonlybooleanfalse是否只读模式
disabledbooleanfalse是否禁用表单

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} />;
};

最佳实践

  1. 合理使用 Schema 结构:将复杂表单拆分为多个对象层级
  2. 组件复用:抽取通用的 Schema 配置
  3. 性能优化:大表单使用分步骤渲染
  4. 用户体验:提供清晰的验证提示和加载状态
  5. 类型安全:使用 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:

  1. 使用 React.memo 包装自定义组件
  2. 避免在 render 中创建新的 schema 对象
  3. 大表单考虑分页或分步骤渲染
  4. 合理使用 shouldUpdate 控制组件更新
资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/904,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?