JSON Schema 表单

作者: 四哥0819 | 来源:发表于2017-04-07 00:03 被阅读3578次

    前端的同学对 JSON 都应该是非常熟悉的,所以今天我们讨论的问题应该是很好理解的。

    先来看下 JSON Schema 这个东西,我直接引用官网的描述。

    JSON Schema is a vocabulary that allows you to annotate and validate JSON documents.

    英文很烂的我自然是看不懂的,所以我再直接引用翻译软件的翻译。

    JSON模式是一个允许您注释和验证JSON文档的词汇。

    翻译的也还是看不懂的,但是大概能理解JSON Schema的意思,也就是一个JSON文档可以用另一个JSON去描述。

    举一个简单的栗子:

    //这是一个 JSON 文档
    {
        "name": "zhuss"
    }
    //这是描述上面 JSON 的文档
    {
       "type":"object",
       "properties":{
            "name":{
                "type":"string"
            }
        }
    }
    

    栗子说明了概念就是这么简单,那如何在实际的中使用到这个东西,在什么时候可以用到这样的东西呢,感觉好像没有什么地方能够用到这样的技术呀。

    答案是,有些比较简单数据需要运营配置的时候,但是运营是不会写JSON文档的,必须做成可视化的表单,运营才会填相应的数据。但是,我们不想花时间针对每个配置写一个表单页面,所以就可以运用上面的概念,做一个一劳永逸的模板,我们(程序员哥哥)写好 JSON Schema,对应生成一个表单让运营去填,提交的表单就是一个 JSON 文档了。

    GitHub 上关于 jsonschema-form 的项目是这个react-jsonschema-form

    如果我们不是 react 项目,而且我们用的 ui 框架bootstrap怎么办?其实我们可以在项目中简单的使用 JSON Schema 来完成我们的需求。

    比如我用 Vue.js,ui用的是ElementUI,实现简单的 JSON Schema Form模板。

    首先,确定我们的 JSON 文档是简单形式的,最多嵌套一层数组。因为表单的形式输出的 JSON 文档一般都是单层的JSON,如果层级多了,那这个表单就无法组织了。

    我们准备一份需要的JSON文档,对应的输出一份JSON Schema文档。

    //json文档
    {
        "title": "标题",
        "tasks": [
            {
                "title": "名称",
                "details": "13123",
                "done": true
            }
        ]
    }
    
    //对应的Schema文档
    {
        "title": "测试配置",
        "type": "object",
        "required": [
            "title"
        ],
        "properties": {
            "title": {
                "type": "string",
                "title": "Task list title"
            },
            "tasks": {
                "type": "array",
                "title": "Tasks",
                "items": {
                    "type": "object",
                    "required": [
                        "title"
                    ],
                    "properties": {
                        "title": {
                            "type": "string",
                            "title": "Title",
                            "description": "A sample title"
                        },
                        "details": {
                            "type": "string",
                            "title": "Task details",
                            "description": "Enter the task details"
                        },
                        "done": {
                            "type": "boolean",
                            "title": "Done?",
                            "default": false
                        }
                    }
                }
            }
        }
    }
    

    下面是我书写的一份Html 表单模板

    <div class="form">
          <el-form :model="formData">
            <div v-for="(item,key) in jsonSchema.properties">
              <!--单层-->
              <el-form-item :label="item.title" v-if="item.type=='string'">
                <el-input v-model="formData[key]"></el-input>
              </el-form-item>
              <el-form-item :label="item.title" v-if="item.type=='integer'">
                <el-input v-model="formData[key]"></el-input>
              </el-form-item>
              <el-form-item :label="item.title" v-if="item.type==='boolean'">
                <el-switch v-model="formData[key]"></el-switch>
              </el-form-item>
              <!--单层 end-->
              <!--嵌套array-->
              <div v-if="item.type==='array'">
                <div class="array-title">
                  <p class="array-title-text">
                    <span>{{item.title}}</span>
                  </p>
                  <p>
                    <el-button @click="addBtnClick(item.items.properties,key)">+添加</el-button>
                  </p>
                </div>
                <div class="array-content" v-for="(initem,index) in formData[key]">
                  <!--array对象-->
                  <div class="array-obj">
                    <div v-for="(i,k) in item.items.properties">
                      <el-form-item :label="i.title" v-if="i.type==='string'">
                        <el-input v-model="initem[k]"></el-input>
                      </el-form-item>
                      <el-form-item :label="i.title" v-if="i.type==='number'">
                        <el-input-number v-model="initem[k]"></el-input-number>
                      </el-form-item>
                      <el-form-item :label="i.title" v-if="i.type==='boolean'">
                        <el-switch v-model="initem[k]"></el-switch>
                      </el-form-item>
                    </div>
                  </div>
                  <!--array对象 end-->
                  <!--操作按钮-->
                  <div class="array-btns">
                    <p>
                      <el-button @click="moveBtnClick(index,index-1,key)" :disabled="index==0">上移</el-button>
                    </p>
                    <p>
                      <el-button @click="moveBtnClick(index,index+1,key)" :disabled="index==formData[key].length-1">下移</el-button>
                    </p>
                    <p>
                      <el-button @click="delBtnClicl(index,key)">删除</el-button>
                    </p>
                  </div>
                  <!--操作按钮 end-->
                </div>
              </div>
              <!--嵌套array end-->
            </div>
            <div style="padding-top:5px;">
              <el-form-item>
                <el-button @click="submitBtnClick">提交</el-button>
              </el-form-item>
            </div>
          </el-form>
        </div>
        <!--form-->
    

    如果是没有嵌套array的简单 JSON ,那简单不过了,但是难免会有嵌套的。值得注意的是嵌套,需要有一些按钮操作。

    比如向array中添加对象,删除对象,移动对象顺序等。。。

    //添加数组
          addBtnClick(item, key) {
            var obj = {};
            for (var i in item) {
              if (item[i].type == "boolean") {
                obj[i] = false;
              } else {
                obj[i] = "";
              }
            }
            if (this.formData[key]) {
              this.formData[key].push(obj);
            } else {
              this.formData[key] = [];
              this.formData[key].push(obj);
            }
            this.formData = this.formData;
          },
          //删除数组
          delBtnClicl(index, key) {
            this.formData[key].splice(index, 1);
          },
          //移动
          moveBtnClick(firstIndex, lastIndex, key, ) {
            var first = JSON.parse(JSON.stringify(this.formData[key][firstIndex]));
            var last = JSON.parse(JSON.stringify(this.formData[key][lastIndex]));
            for (var i in first) {
              this.formData[key][lastIndex][i] = first[i];
            };
    
            for (var i in last) {
              this.formData[key][firstIndex][i] = last[i];
            }
          }
    

    最终渲染出来的模板下图所示:

    Paste_Image.png

    上诉例子简化了表单,如果可以,借鉴 react-jsonschema-form 是一个比较不错的选择。

    相关文章

      网友评论

        本文标题:JSON Schema 表单

        本文链接:https://www.haomeiwen.com/subject/uxqwottx.html