Jsonshcema转前端表单

要将给定的 JSON Schema 转换为可视化的前端表单界面,首先需要解析 JSON Schema 的结构,然后动态生成相应的 HTML 表单元素。这涉及到以下几个步骤:

  1. 解析 JSON Schema:遍历 JSON Schema,识别其 typeproperties
  2. 动态生成表单元素:根据不同的 type(如 objectarraystring 等)生成对应的表单元素,并根据 required 字段标识必填项。
  3. 处理嵌套结构:对于 objectarray 类型的字段,需要递归生成子表单元素。

代码实现步骤

1. 解析 JSON Schema 并生成表单
function renderFormFromSchema(schema, parentContainer = document.getElementById('fieldsContainer')) {
    for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {
        const fieldContainer = document.createElement('div');
        fieldContainer.className = 'field-container';

        const isRequired = schema.required && schema.required.includes(fieldName);

        // 创建字段名称输入框
        const nameInput = document.createElement('input');
        nameInput.type = 'text';
        nameInput.className = 'field-name';
        nameInput.value = fieldName;
        nameInput.disabled = true; // 禁用字段名称输入框,用户不能修改
        fieldContainer.appendChild(createFieldLabel('字段名称: ', nameInput));

        // 创建字段类型选择框
        const typeSelect = document.createElement('select');
        typeSelect.className = 'field-type';
        typeSelect.disabled = true; // 禁用字段类型选择框,用户不能修改
        ['string', 'number', 'object', 'array', 'boolean'].forEach(type => {
            const option = document.createElement('option');
            option.value = type;
            option.text = type;
            if (type === fieldSchema.type) {
                option.selected = true;
            }
            typeSelect.appendChild(option);
        });
        fieldContainer.appendChild(createFieldLabel('字段类型: ', typeSelect));

        // 创建是否必填复选框
        const requiredCheckbox = document.createElement('input');
        requiredCheckbox.type = 'checkbox';
        requiredCheckbox.className = 'field-required';
        requiredCheckbox.checked = isRequired;
        requiredCheckbox.disabled = true; // 禁用必填复选框,用户不能修改
        fieldContainer.appendChild(createFieldLabel('是否必填: ', requiredCheckbox));

        // 处理嵌套字段
        if (fieldSchema.type === 'object' || fieldSchema.type === 'array') {
            const nestedContainer = document.createElement('div');
            nestedContainer.className = 'nested-container';
            nestedContainer.style.display = 'block';
            fieldContainer.appendChild(nestedContainer);

            const nestedBtn = document.createElement('button');
            nestedBtn.type = 'button';
            nestedBtn.className = 'nested-btn';
            nestedBtn.textContent = '添加嵌套字段';
            nestedBtn.style.display = 'block';
            nestedBtn.disabled = true; // 禁用添加嵌套字段按钮,用户不能操作
            fieldContainer.appendChild(nestedBtn);

            if (fieldSchema.type === 'object') {
                renderFormFromSchema(fieldSchema, nestedContainer);
            } else if (fieldSchema.type === 'array' && fieldSchema.items) {
                renderFormFromSchema({ type: 'object', properties: fieldSchema.items }, nestedContainer);
            }
        }

        parentContainer.appendChild(fieldContainer);
    }
}

function createFieldLabel(labelText, inputElement) {
    const label = document.createElement('label');
    label.textContent = labelText;
    const fieldLabel = document.createElement('div');
    fieldLabel.className = 'field-label';
    fieldLabel.appendChild(label);
    fieldLabel.appendChild(inputElement);
    return fieldLabel;
}
2. 调用 renderFormFromSchema 函数

假设你有一个 JSON Schema,如下所示:

{
  "type": "object",
  "properties": {
    "person": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "age": { "type": "number" },
        "address": {
          "type": "object",
          "properties": {
            "city": { "type": "string" },
            "zipcode": { "type": "string" }
          },
          "required": ["city"]
        }
      },
      "required": ["name", "address"]
    }
  },
  "required": ["person"]
}

你可以通过以下方式生成对应的前端表单:

const schema = {
  "type": "object",
  "properties": {
    "person": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "age": { "type": "number" },
        "address": {
          "type": "object",
          "properties": {
            "city": { "type": "string" },
            "zipcode": { "type": "string" }
          },
          "required": ["city"]
        }
      },
      "required": ["name", "address"]
    }
  },
  "required": ["person"]
};

document.addEventListener('DOMContentLoaded', () => {
    renderFormFromSchema(schema);
});
3. 结果解释
  • 禁用输入控件: 在生成的表单中,所有输入控件和选择框都被禁用(disabled),以显示 JSON Schema 的结构而不允许用户修改。这可以帮助用户直观地看到 JSON Schema 的定义。

  • 递归处理嵌套结构: 对于嵌套的 objectarray,会递归生成其子结构的表单元素。

扩展功能

如果你希望允许用户修改表单元素以便更新 JSON Schema,可以移除 disabled 属性,并添加表单输入变化的事件处理逻辑。

这个示例只是一个基本的实现,你可以根据需要扩展它,添加更多的验证、样式和功能。
下面是一个完整的 HTML 页面代码示例,它可以根据给定的 JSON Schema 动态生成相应的表单结构,并显示在页面上。页面使用简单的 HTML 和 JavaScript 来解析和渲染 JSON Schema。

完整的前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON Schema to Form</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }

        .field-container {
            margin-bottom: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            border-radius: 5px;
        }

        .field-label {
            margin-bottom: 10px;
        }

        .nested-container {
            margin-top: 20px;
            padding-left: 20px;
            border-left: 2px solid #ddd;
        }

        label {
            font-weight: bold;
            display: block;
            margin-bottom: 5px;
        }

        input[type="text"], select {
            width: 100%;
            padding: 5px;
            margin-bottom: 10px;
        }

        input[type="checkbox"] {
            margin-left: 5px;
        }

        .nested-btn {
            display: block;
            margin-top: 10px;
        }
    </style>
</head>
<body>

    <h1>JSON Schema to Form</h1>
    <div id="fieldsContainer"></div>

    <script>
        function renderFormFromSchema(schema, parentContainer = document.getElementById('fieldsContainer')) {
            for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {
                const fieldContainer = document.createElement('div');
                fieldContainer.className = 'field-container';

                const isRequired = schema.required && schema.required.includes(fieldName);

                // 创建字段名称输入框
                const nameInput = document.createElement('input');
                nameInput.type = 'text';
                nameInput.className = 'field-name';
                nameInput.value = fieldName;
                nameInput.disabled = true; // 禁用字段名称输入框,用户不能修改
                fieldContainer.appendChild(createFieldLabel('字段名称: ', nameInput));

                // 创建字段类型选择框
                const typeSelect = document.createElement('select');
                typeSelect.className = 'field-type';
                typeSelect.disabled = true; // 禁用字段类型选择框,用户不能修改
                ['string', 'number', 'object', 'array', 'boolean'].forEach(type => {
                    const option = document.createElement('option');
                    option.value = type;
                    option.text = type;
                    if (type === fieldSchema.type) {
                        option.selected = true;
                    }
                    typeSelect.appendChild(option);
                });
                fieldContainer.appendChild(createFieldLabel('字段类型: ', typeSelect));

                // 创建是否必填复选框
                const requiredCheckbox = document.createElement('input');
                requiredCheckbox.type = 'checkbox';
                requiredCheckbox.className = 'field-required';
                requiredCheckbox.checked = isRequired;
                requiredCheckbox.disabled = true; // 禁用必填复选框,用户不能修改
                fieldContainer.appendChild(createFieldLabel('是否必填: ', requiredCheckbox));

                // 处理嵌套字段
                if (fieldSchema.type === 'object' || fieldSchema.type === 'array') {
                    const nestedContainer = document.createElement('div');
                    nestedContainer.className = 'nested-container';
                    nestedContainer.style.display = 'block';
                    fieldContainer.appendChild(nestedContainer);

                    const nestedBtn = document.createElement('button');
                    nestedBtn.type = 'button';
                    nestedBtn.className = 'nested-btn';
                    nestedBtn.textContent = '添加嵌套字段';
                    nestedBtn.style.display = 'block';
                    nestedBtn.disabled = true; // 禁用添加嵌套字段按钮,用户不能操作
                    fieldContainer.appendChild(nestedBtn);

                    if (fieldSchema.type === 'object') {
                        renderFormFromSchema(fieldSchema, nestedContainer);
                    } else if (fieldSchema.type === 'array' && fieldSchema.items) {
                        renderFormFromSchema({ type: 'object', properties: fieldSchema.items }, nestedContainer);
                    }
                }

                parentContainer.appendChild(fieldContainer);
            }
        }

        function createFieldLabel(labelText, inputElement) {
            const label = document.createElement('label');
            label.textContent = labelText;
            const fieldLabel = document.createElement('div');
            fieldLabel.className = 'field-label';
            fieldLabel.appendChild(label);
            fieldLabel.appendChild(inputElement);
            return fieldLabel;
        }

        // 示例 JSON Schema
        const schema = {
          "type": "object",
          "properties": {
            "person": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "age": { "type": "number" },
                "address": {
                  "type": "object",
                  "properties": {
                    "city": { "type": "string" },
                    "zipcode": { "type": "string" }
                  },
                  "required": ["city"]
                }
              },
              "required": ["name", "address"]
            }
          },
          "required": ["person"]
        };

        // 页面加载后渲染表单
        document.addEventListener('DOMContentLoaded', () => {
            renderFormFromSchema(schema);
        });
    </script>

</body>
</html>

代码解释

  1. HTML 结构:

    • 页面包含一个用于显示表单的 div,即 #fieldsContainer
    • 采用了简单的样式,用来区分不同的字段和嵌套结构。
  2. JavaScript 功能:

    • renderFormFromSchema 函数递归解析 JSON Schema,动态生成对应的表单结构。
    • createFieldLabel 函数简化了标签和输入控件的创建过程。
    • 示例 JSON Schema 定义在脚本中,在页面加载完成后自动渲染到表单中。
  3. 禁用状态:

    • 表单元素被禁用(disabled),以展示 JSON Schema 的结构,而非供用户编辑。你可以通过移除 disabled 属性使其可编辑。

如何使用

  1. 打开页面:

    • 将上述代码保存为 index.html 文件,然后在浏览器中打开,即可看到生成的表单。
  2. 修改 JSON Schema:

    • 可以修改示例中的 schema 对象,以生成不同结构的表单。

这段代码为你提供了一个简单的框架,可以根据 JSON Schema 动态生成表单,并在页面上展示。你可以根据需要进一步扩展功能,比如增加编辑功能或保存修改后的 Schema。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值