vue2+antvue的json驱动的表单(支持多行多项)

该段代码展示了如何使用 Vue 和 Ant Design Vue 库动态生成表单,包括不同类型的输入字段如文本、数字、选择器、开关等,并支持多行多项输入。表单数据的设置、获取和验证功能也一并实现,允许用户添加、删除行以及转换数据格式。
摘要由CSDN通过智能技术生成
// 需要传入构造项-formItems对象数组来生成表单

// 对象可配置属性name(必须),label(必须),type(默认text),default,required(默认true),disabled(默认false),onBlur,onFocus
// type可设为number(数字)
//          select(选择器),需要配套options对象(同antd),拥有onDropdown事件(展开项)
//          switch(开关),默认值false
//          mul(多行多项),值为一个数组
//          obj(对象),值为一个对象,本质是不可新增行的mul
//          kvObj(键值对对象),值为一个对象
// 通过调用setValue()方法赋值给表单,调用getValue()方法获取表单数据,getValueByName()方法可以获得单个值...

<template>
  <a-form-model ref="ruleForm" :model="form">
    <div v-for="formItem in formItems" :key="formItem.name">
      <!-- 简单型 -->
      <template v-if="!isMulType(formItem)">
        <a-form-model-item
          :label="formItem.label"
          :prop="formItem.name"
          :wrapper-col="{ span: wrapperWidth }"
          :label-col="{ span: labelWidth }"
          :rules="formItem.required !== false ? { required: true, message: `请输入${formItem.label}` } : undefined"
        >
          <!-- 类型枚举 -->
          <!-- 普通input -->
          <a-input
            v-if="!formItem.type"
            v-model="form[formItem.name]"
            :disabled="formItem.disabled"
            @blur="formItem.onBlur && formItem.onBlur()"
            @focus="formItem.onFocus && formItem.onFocus()"
          />
          <!-- number型 -->
          <a-input-number
            style="width: 100%"
            v-if="formItem.type === 'number'"
            v-model="form[formItem.name]"
            :min="formItem.min || undefined"
            :max="formItem.max || undefined"
            :disabled="formItem.disabled"
            @blur="formItem.onBlur && formItem.onBlur()"
            @focus="formItem.onFocus && formItem.onFocus()"
          />
          <!-- select型 -->
          <a-select
            v-if="formItem.type === 'select'"
            v-model="form[formItem.name]"
            :options="formItem.options"
            :disabled="formItem.disabled"
            allow-clear
            :get-popup-container="triggerNode => (triggerNode.parentNode || document.body)"
            :show-search="true"

            @blur="formItem.onBlur && formItem.onBlur()"
            @focus="formItem.onFocus && formItem.onFocus()"
            @dropdownVisibleChange="formItem.onDropdown ? formItem.onDropdown() : {}"
          />
          <!-- auto -->
          <a-auto-complete
            v-if="formItem.type === 'auto'"
            v-model="form[formItem.name]"
            :data-source="formItem.options"
            :disabled="formItem.disabled"
            :filter-option="true"
            :get-popup-container="triggerNode => (triggerNode.parentNode || document.body)"
            @blur="formItem.onBlur && formItem.onBlur()"
            @focus="formItem.onFocus && formItem.onFocus()"
          />
        </a-form-model-item>
      </template>

      <template v-else>
        <!-- for渲染多行 -->
        <div v-for="(childValue, index) in form[formItem.name]" :key="formItem.name + index">
          <!-- for渲染多项 -->
          <div
            v-for="(child, num) in formItem.children"
            :key="child.name"
          >
            <a-form-model-item
              style="margin:0"
              :wrapper-col="{ span: wrapperWidth, offset: num === 0 ? 0 : labelWidth }"
              :label-col="{ span: labelWidth }"
              :label="num === 0 ? formItem.label : false"
              :prop="`${formItem.name}.${index}.${child.name}`"
              :rules="child.required !== false ? { required: true, message: `请输入${child.label}` } : undefined"
            >
              <!-- 类型枚举 -->
              <!-- input -->
              <a-input
                :placeholder="child.name"
                v-model="childValue[child.name]"
                v-if="!child.type"
                :disabled="formItem.disabled"
                @blur="formItem.onBlur && formItem.onBlur()"
                @focus="formItem.onFocus && formItem.onFocus()"
              />
              <!-- number -->
              <a-input-number
                :placeholder="child.name"
                v-model="childValue[child.name]"
                v-if="child.type === 'number'"
                :disabled="formItem.disabled"
                @blur="formItem.onBlur && formItem.onBlur()"
                @focus="formItem.onFocus && formItem.onFocus()"
              />
              <!-- select -->
              <a-select
                :placeholder="child.name"
                v-model="childValue[child.name]"
                :mode="child.mode || 'default'"
                v-if="child.type === 'select'"
                :options="child.options"
                :disabled="formItem.disabled"
                allow-clear
                @blur="formItem.onBlur && formItem.onBlur()"
                @focus="formItem.onFocus && formItem.onFocus()"
              />
              <!-- switch -->
              <div v-if="child.type === 'switch'">
                <span style="margin-right: 10px">{{ child.label }}:</span>
                <a-switch
                  v-model="childValue[child.name]"
                  :disabled="formItem.disabled"
                  @change="formItem.onChange && formItem.onChange()"
                />
              </div>
              <div v-if="child.type === 'json'">
                <span style="margin-right: 10px">{{ child.label }}:</span>
                <json-editor v-model="childValue[child.name]" />
              </div>
            </a-form-model-item>
          </div>
          <!-- 每行结尾附带添加删除功能 -->
          <a-row>
            <a-col :span="wrapperWidth" :offset="labelWidth" v-if="formItem.type !== 'obj'">
              <a-form-model-item>
                <a-popconfirm
                  title="确定删除该项吗?"
                  v-if="form[formItem.name].length > 1"
                  @confirm="deleteVal(formItem.name, index)"
                >
                  <a-button type="danger" size="small" style="margin-right:10px;">
                    删除
                  </a-button>
                </a-popconfirm>
                <a-button
                  size="small"
                  v-if="index === form[formItem.name].length - 1"
                  @click="addVal(formItem.name)"
                >
                  添加
                </a-button>
              </a-form-model-item>
            </a-col>
          </a-row>
        </div>
      </template>
    </div>
  </a-form-model>
</template>
<script>
export default {
  data() {
    return {
      form: {}
    };
  },
  props: {
    formItems: {
      required: true,
      type: Array,
      default: () => []
    },
    labelWidth: {
      required: false,
      type: Number,
      default: 6
    },
    wrapperWidth: {
      required: false,
      type: Number,
      default: 22 - 6
    }
  },
  methods: {
    // 判断是否为多行多项类型
    isMulType(obj) {
      if (obj.type === undefined) {
        return false;
      } else if (['mul', 'obj', 'kvObj'].includes(obj.type)) {
        return true;
      } else {
        return false;
      }
    },
    // 删除行
    deleteVal(name, index) {
      this.form[name].splice(index, 1);
    },
    // 新增行
    addVal(name) {
      const names = this.formItemObj[name].children.map(item => item.name);
      const tempObj = {};
      names.forEach(item => {
        tempObj[item] = undefined;
      });
      // 初始值
      this.formItemObj[name].children.forEach(item => {
        tempObj[item.name] = item.default || undefined;
      });
      this.form[name].push(tempObj);
    },
    // 重置表单并添加新增基础项/初值
    reset() {
      this.form = {};
      this.$refs.ruleForm.resetFields();
      for (let formItem of this.formItems) {
        if (this.isMulType(formItem)) {
          this.$set(this.form, formItem.name, []);
          this.addVal(formItem.name);
        } else {
          this.$set(this.form, formItem.name, formItem.default);
        }
      }
    },
    // 设定值
    setValue(formData) {
      this.reset();
      Object.entries(formData).forEach(([key, value]) => {
        // 对值进行拷贝再操作
        if (typeof value === 'object') {
          value = JSON.parse(JSON.stringify(value));
        }
        // 设定项不存在,跳过
        if (this.formItemObj[key] === undefined) {
          return;
        }
        // 设定值不存在,且为多项类型
        if (value === null || value === undefined) {
          // 若赋值发现长度为0,需要进行新增初始项
          if (this.isMulType(this.formItemObj[key]) && this.form[key].length === 0) {
            this.addVal(this.formItemObj[key].name);
          }
        } else if (this.formItemObj[key].type === 'obj') {
          // 对象{xx: xxx}转为数组[{xx: xxx}]
          this.$set(this.form, key, [value]);
        } else if (this.formItemObj[key].type === 'kvObj') {
          // kv对象{key1: xxx, key2: xxx}转为数组[{key: key1, value: xxx}, {...}]
          const result = Object.keys(value).map(item => ({ key: item, value: value[item] }));
          this.$set(this.form, key, result);
        } else {
          // 其他正常赋值
          this.$set(this.form, key, value);
        }
      });
    },
    // 输出值
    getValue() {
      let tempForm = {};
      this.$refs.ruleForm.validate(valid => {
        if (!valid) {
          tempForm = false;
          return;
        }
        // 处理数据格式
        Object.entries(this.form).forEach(([key, value]) => {
          if (this.formItemObj[key].type === 'mul') {
            // 删除数组空对象
            const result = [];
            value.forEach(item => {
              if (Object.keys(item).length === 0) {
                return;
              }
              if (Object.values(item).every(o => o === undefined)) {
                return;
              }
              result.push(item);
            });
            tempForm[key] = result;
          } else if (this.formItemObj[key].type === 'obj') {
            // 数组[{xx: xxx}]转为对象{xx: xxx}
            tempForm[key] = value[0];
          } else if (this.formItemObj[key].type === 'kvObj') {
            // 数组[{key: key1, value: xxx}, {...}]转为kv对象{key1: xxx, key2: xxx}
            const result = {};
            value.forEach(item => {
              if (item.key !== undefined && item.key.trim() !== '') {
                result[item.key] = item.value;
              }
            });
            tempForm[key] = result;
          } else {
            // 其他正常赋值
            tempForm[key] = value;
          }
        });
      });
      return tempForm;
    },
    // 获得一个值
    getValueByName(name) {
      const value = this.form[name];
      if (this.formItemObj[name].type === 'obj') {
        // 数组[{xx: xxx}]转为对象{xx: xxx}
        return value[0];
      } else if (this.formItemObj[name].type === 'kvObj') {
        // 数组[{key: key1, value: xxx}, {...}]转为kv对象{key1: xxx, key2: xxx}
        const result = {};
        value.forEach(item => {
          if (item.key !== undefined && item.key.trim() !== '') {
            result[item.key] = item.value;
          }
        });
        return result;
      } else {
        // 其他正常
        return value;
      }
    },
    // 传入一个值
    setValueByName(name, data) {
      // 对值进行拷贝再操作
      if (typeof data === 'object') {
        data = JSON.parse(JSON.stringify(data));
      }
      if (this.formItemObj[name].type === 'obj') {
        // 对象{xx: xxx}转为数组[{xx: xxx}]
        this.$set(this.form, name, [data]);
      } else if (this.formItemObj[name].type === 'kvObj') {
        // kv对象{key1: xxx, key2: xxx}转为数组[{key: key1, value: xxx}, {...}]
        const result = Object.keys(data).map(item => ({ key: item, value: data[item] }));
        this.$set(this.form, name, result);
      } else {
        // 其他正常赋值
        this.$set(this.form, name, data);
      }
    }
  },
  mounted() {
    this.reset();
  },
  computed: {
    // 改为键值对的方式易于检索
    formItemObj() {
      const temp = {};
      this.formItems.forEach(formItem => {
        temp[formItem.name] = formItem;
      });
      return temp;
    }
  }
};
</script>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值