el-form表单使用递归组件实现动态渲染&表单嵌套(输入框、下拉选择框、单选、数组、对象数组...)

最近项目提了一个需求,要求根据后端返回的数据在表单里展示各种类型的组件,包括但不限于输入框、单选按钮、表格...简而言之,后端传的数据里,就是会出现对象嵌套对象的数据,嵌套多少层是未知的o(╥﹏╥)o 下面的代码是经过一次次的迭代产生的.

父组件:

  
       
 

{{ item.annotation }}

1.headerData.external是要渲染的表单结构,是数组类型的数据,结构如下:

[{
		"name": "attr1",// 属性的英文名称,一般用于获取对应数据或者是el-form-item绑定的prop
		"type": "string",// 此处可能是c++数据类型或者js数据类型亦或者是自定义类型等等,满足开发需要即可
		"annotation": "属性1",// 属性的中文名称,一般用于展示,用于el-form-item绑定的label
		"isArray": 0 // 用来决定是否以表格展示
	}, {
		"name": "wqrwe",
		"type": "scwrefer",// 自定义类型
		"annotation": "某某",
		"isArray": 0,
		"children": [{
			"name": "tyi",
			"type": "double",
			"annotation": "不知道",
			"isArray": 0
		}, {
			"name": "ytuiyt",
			"type": "double",
			"annotation": "不知道",
			"isArray": 0
		}, {
			"name": "ewrtgwer",
			"type": "double",
			"annotation": "不知道",
			"isArray": 0
		}],// 可能会出现表单嵌套表单,在数据上体现就是对象嵌套
	}]

递归组件:

HTML代码:


      
      
      
      
      
      
    

js代码:

// 判断右侧信息面板属性类型来决定组件类型
    componentsByType(temp) {
      let obj = { compType: "", inputType: "" };
// dataType是声明的一个对象,里面是描述的前后端数据对应关系,比如说后端的int对应前端的number等
      switch (dataType[temp.type]) {
        case "number":
          obj.compType = "input";
          obj.inputType = "number";
          break;
        case "boolean":
          obj.compType = "radio";
          break;
        case "string":
        case "undefined":
        case "null":
          obj.compType = "input";
          obj.inputType = "string";
          break;
        default:
          obj.compType = undefined;
      }
      return obj;
    },
// 往数组里添加一条数据 push进去
addBase(item) {
      // ...
      this.$forceUpdate();
    },
// 删除数组的一条数据 使用splice
    deleteBase(item, index) {
      arr.splice(index, 1);
    },

非基本类型数组组件:

添加

js代码:

// 添加一条记录
    addData() {
      let obj = {};
// 递归方法为数组添加一条数据,避免表格内嵌套的是多层结构
      this.dealAttr(this.headerData, obj).then((res) => {
        this.formValue[this.headerData.name].push(res);
        this.$forceUpdate();
      });
    },
    // 处理属性
    dealAttr(attr, data) {
      if (attr.children) {
        for (let ele of attr.children) {
          if (!ele.children) {
            if (this.componentsByType(ele) == "string") {
                this.$set(data, ele.name, ele.isArray == 1 ? [] : "");
                this.$forceUpdate();
              } else if (this.componentsByType(ele) == "number") {
                this.$set(data, ele.name, ele.isArray == 1 ? [] : 0);
                this.$forceUpdate();
              }
          } else {
            if (ele.isArray == 1) {
              this.$set(data, ele.name, []);
              this.$forceUpdate();
            } else {
               this.$set(data, ele.name, {});
                this.$forceUpdate();
                this.dealAttr(ele, data[ele.name]);
            }
          }
        }
      }
      return Promise.resolve(data);
    },
    // 删除一条记录
    deleteData(name, index) {
      this.formValue[name].splice(index, 1);
    },

 非基本类型表单组件:

代码没有全放,因为每个人碰到的需求可能都不一样,大概的逻辑都在。

本人接触前端两年,归来仍是菜鸟,这是我目前能想到的满足需求的方法,如果您有更好的想法,欢迎一起讨论~

你可能感兴趣的:(vue.js,前端,javascript)