vue2的element自定义表单(支持数据联动和表单联动)

7 篇文章 0 订阅
文章展示了如何使用Vue.js创建一个动态表单,包括不同类型的输入控件(如选择框、单选按钮、复选框、输入框等),并处理表单数据的验证、变化事件以及依赖关系。同时,文章也包含了一个自定义组件的使用,该组件接收外部数据,更新表单选项,并触发事件来更新父组件的状态。
摘要由CSDN通过智能技术生成

1. 表单部分

  1. template
<template>
  <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="120px" 
  	@submit.native.prevent
  	class="demo-ruleForm">
    <el-form-item
      v-for="(item, index) in formColumns"
      :key="index"
      :label="item.label"
      :prop="item.prop"
    >
      <el-select
        v-if="item.type === 'select'"
        v-model="ruleForm[item.prop]"
        :disabled="item.disabled"
        :placeholder="exportPlaceholder(item.placeholder, item)"
        @change="selectChange(item)"
      >
        <el-option v-for="(each, i) in item.options" :key="i" 
        	:label="each.label" :value="each.value" />
      </el-select>
      
      <el-radio-group  v-if="item.type === 'radioGroup'" v-model="ruleForm[item.prop]">
      	<el-radio  v-for="(each, i) in item.options" :key="i" :label="item.value">{{ item.label }}</el-radio>
      </el-radio-group>
      
	  <el-checkbox-group  v-if="item.type === 'checkboxGroup'" v-model="ruleForm[item.prop]">
      	<el-checkbox  v-for="(each, i) in item.options" :key="i" :label="item.value">{{ item.label }}</el-checkbox>
      </el-checkbox-group>
      
      <el-input-number v-else-if="item.type === 'inputNumber'" 
      	v-model="ruleForm[item.prop]" 
      	controls-position="right" 
      	:disabled="item.disabled"
      	/>
      	
      <el-input
        v-else-if="item.type === 'input.number'"
        v-model.number="ruleForm[item.prop]"
        :disabled="item.disabled"
        :placeholder="exportPlaceholder(item.placeholder, item)"
      />
      
      <template v-else-if="item.type === 'password'">
        <el-input v-model="ruleForm[item.prop]" show-password type="password" 
        	:disabled="item.disabled"
        	autocomplete="off" 
        	:placeholder="exportPlaceholder(item.placeholder, item)"
        	 />
      </template>
      
      <el-input v-else-if="item.type === 'textarea'" 
      	v-model="ruleForm[item.prop]" type="textarea" 
      	:disabled="item.disabled"
      	:placeholder="exportPlaceholder(item.placeholder, item)" />
      	
      <el-input v-else v-model="ruleForm[item.prop]" :placeholder="exportPlaceholder(item.placeholder, item)" />
    </el-form-item>
    
    <el-form-item v-if="useSubmit || useCancel">
      <el-button v-if="useSubmit" type="primary" @click="submitForm">保存</el-button>
      <el-button v-if="useCancel" @click="cancelForm">关闭</el-button>
    </el-form-item>
  </el-form>
</template>

2.js

function isEmpty(val) {
  return val === null || val === undefined || val === '';
}
function notEmpty(val) {
  return val !== null && val !== undefined && val !== '';
}

export default {
  props: {
    useSubmit: {
      type: Boolean,
      default() {
        return false;
      }
    },
    useCancel: {
      type: Boolean,
      default() {
        return false;
      }
    },
    defaultData: {
      type: Object,
      default() {
        return {};
      }
    },
    formObj: {
      type: Object,
      default() {
        return {};
      }
    },
    formList: {
      type: Array,
      default() {
        return [];
      }
    },
    optionsObj: {
      type: Object,
      default() {
        return {};
      }
    }
  },
  data() {
    return {
      formColumns: [],
      ruleForm: {},
      rules: {}
    };
  },
  watch: {
    defaultData() {
      this.setForm(true);
    }
  },
  created() {
    this.initOptions();

    this.setForm(true);
  },
  mounted() {
    // this.setForm();
  },
  methods: {
    notEmpty,

    //  下拉框切换
    selectChange(item) {
      if (item) {
        const { ruleForm } = this;
        if (item.hasOwnProperty('map')) {
          this.clearMapOtherFormItems(item.map, ruleForm[item.prop]);
          this.setForm();
        } else if (item.hasOwnProperty('affect')) {
          const result = this.handleAffectValue(item.affect, item);
          this.$emit('updateOptions', {
            // updateList: [],
            // cleanList: [],
            ...result,
            formData: JSON.parse(JSON.stringify(ruleForm))
          });
        }
      }
    },

    //  处理影响数据
    handleAffectValue(affect, data) {
      const updateList = [];
      const cleanList = [];
      let targetAffect = affect;
      const { formColumns, ruleForm } = this;
      formColumns.some(item => {
        if (item && item.prop === targetAffect) {
          let value = '';
          value = notEmpty(item.defaultValue) ? item.defaultValue : (item.type === '' ? '' : '');
          ruleForm[item.prop] = value;
          if (affect === targetAffect) {
            updateList.push({ source: data.prop, target: targetAffect });
          } else {
            cleanList.push(targetAffect);
          }

          if (notEmpty(item.affect)) {
            targetAffect = item.affect;
          } else {
            return true;
          }
        }
      });

      return {
        updateList, cleanList
      };
    },

    //  初始化表单所需的选择数据地址,方便后续配置
    initOptions() {
      const { formObj, optionsObj } = this;
      Object.keys(formObj).forEach(item => {
        if (optionsObj.hasOwnProperty(item) && formObj[item].type === 'select') {
          this.$set(formObj[item], 'options', optionsObj[item]);
        }
      });
    },

    //  设置表单
    setForm(isInit) {
      const { formList, formColumns, ruleForm, rules, defaultData } = this;

      //  1.先配置表单所用参数
      const list = [];
      this.setFormColumns(formList, list, isInit ? defaultData : ruleForm, isInit);
      formColumns.splice(0, formColumns.length, ...list);

      const props = list.map(item => item.prop);
      //  2.清除非表单所用参数的其他数据
      Object.keys(ruleForm).forEach(item => {
        if (props.indexOf(item) < 0) {
          this.$delete(ruleForm, item);
          this.$delete(rules, item);
        }
      });

      // const data = JSON.parse(JSON.stringify(ruleForm));

      //  3.再按参数生成表单各项参数
      for (let index = 0; index < formColumns.length; index++) {
        const item = formColumns[index];
        const arr = formColumns;
        // formColumns.forEach((item, index, arr) => {
        let value = '';
        if (isInit) {
          if (notEmpty(defaultData[item.prop])) {
            value = defaultData[item.prop];
          }
        }

        if (isEmpty(value)) {
          value = notEmpty(item.defaultValue) ? item.defaultValue : (item.type === 'checkboxGroup' ? [] : '');
        }

        if (!ruleForm.hasOwnProperty(item.prop) || isInit) {
          this.$set(ruleForm, item.prop, value);
        }

        if (isInit && notEmpty(value)) {
          if (item.map) {
            const { map } = item;
            if (map) {
              Object.keys(map).some(each => {
                if (each === value) {
                  const eachArr = map[value];
                  if (eachArr.length > 0) {
                    const eachAddArr = [];
                    eachArr.forEach(one => {
                      if (!formColumns.find(every => every.prop === one.prop)) {
                        eachAddArr.push(Object.assign({}, formObj[one.prop], JSON.parse(JSON.stringify(one))));
                      } else { /**/ }
                    });

                    arr.splice(index + 1, 0, ...eachAddArr);
                  } else { /**/ }
                  return true;
                } else { /**/ }
              });
            } else { /**/ }
          } else { /**/ }

          if (item.affect) {
            this.$emit('updateOptions', {
              updateList: [{ source: item.prop, target: item.affect }],
              cleanList: [],
              formData: JSON.parse(JSON.stringify(ruleForm))
            });
          }
        }

        if (item.required && !rules.hasOwnProperty(item.prop)) {
          const rule = [];
          if (item.type === 'select') {
            rule.push({ required: true, message: '请选择' + item.label, trigger: 'change' });
          } else {
            rule.push({ required: true, message: '请输入' + item.label, trigger: 'blur' });
          }

		  if (item.rule && item.rule.length > 0) {
            rule.push(...item.rule);
          }

          this.$set(rules, item.prop, rule);
        }
      }
      // });

      this.$nextTick(() => {
        if (this.$refs['ruleForm']) {
          this.$refs['ruleForm'].clearValidate();
        }
      });
    },

    //  用来设置表单所需参数,存在迭代情况
    setFormColumns(list, resultList, data, isInit) {
      const { formObj } = this;
      list.forEach(item => {
        const obj = Object.assign({}, formObj[item.prop], JSON.parse(JSON.stringify(item)));

        resultList.push(obj);

        if (item.hasOwnProperty('map')) {
          const map = item.map;
          if (obj.type === 'checkboxGroup') {
            let arr = [];
            if (data[obj.prop] && data[obj.prop].length > 0) {
              arr = JSON.parse(JSON.stringify(data[obj.prop]));
            } else if (obj.defaultValue && obj.defaultValue.length > 0 && isInit) {
              arr = JSON.parse(JSON.stringify(obj.defaultValue));
            }

            const { optionsObj } = this;
            if (optionsObj[item.prop] && optionsObj[item.prop].length > 0) {
              const options = optionsObj[item.prop].map(item => item.value);
              arr.sort((a, b) => options.indexOf(a) - options.indexOf(b));
            }

            arr.forEach(each => {
              if (notEmpty(each)) {
                const list = map[each];
                if (list && list.length > 0) {
                  this.setFormColumns(list, resultList, data, isInit);
                } else { /**/ }
              } else { /**/ }
            });
          } else {
            const key = isInit ? (notEmpty(data[item.prop]) ? data[item.prop] : item.defaultValue) : data[item.prop];

            const arr = map[key];
            if (arr && arr.length > 0) {
              this.setFormColumns(arr, resultList, data, isInit);
            } else { /**/ }
          }
        }
      });
    },

    //  清理map内其它未匹配的表单数据
    clearMapOtherFormItems(map, key) {
      const { ruleForm, rules } = this;
      Object.keys(map).forEach(item => {
        if (key !== item) {
          map[item].forEach(each => {
            if (ruleForm.hasOwnProperty(each.prop)) {
              this.$delete(ruleForm, each.prop);
              this.$delete(rules, each.prop);
            }

            if (each.hasOwnProperty('map')) {
              this.clearMapOtherFormItems(each.map, key);
            }
          });
        }
      });
    },

    //  关闭表单
    cancelForm() {
      this.$emit('closeForm', this.ruleForm);
    },

    // //  提交表单
    submitForm() {
      this.$refs['ruleForm'].validate((valid) => {
        if (valid) {
          this.$emit('submitForm', this.ruleForm);
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },

    //  重置表单
    resetForm(formName) {
      this.$refs['ruleForm'].resetFields();
    },

    //  输出占位提示
    exportPlaceholder(item) {
      const isSelect = item.type === 'select' || item.type === 'radioGroup' || item.type === 'checkboxGroup';
      return notEmpty(item.placeholder) ? item.placeholder : (`${isSelect ? '选择' : '输入'}${item.label}`);
    }
  }
};

2.调用

1.template

<template>
  <div>
    <CustomForm
      ref="customForm"
      class="pf-form scroll-white"
      :form-obj="formObj"
      :form-list="formList"
      :default-data="defaultData"
      :options-obj="optionsObj"
      @updateOptions="updateOptions"
      @submitForm="submitForm"
    />
    <div class="text-center pf-box-ctrl">
      <el-button size="mini" type="primary" @click="submit">保存</el-button>
    </div>
  </div>
</template>
import CustomForm from '@/components/CustomForm/index';

export default {
  components: {
    CustomForm
  },
  data() {
    return {
      defaultData: {},
      formObj: {
        'id': { type: 'select', options: [], required: true },
        'table': { type: 'select', options: [], required: true },
        'keyType': { type: 'select', options: [], required: true },
        'field': { type: 'input', required: true },
      },
      formList: [
        { label: '数据库', prop: 'id', affect: 'table' },
        { label: 'table', prop: 'table' },
        { label: 'Key类型', prop: 'keyType', map: {
          'HASH': [
            { label: 'Field', prop: 'field' }
          ],
          'STRING': []
        }}
      ],
      optionsObj: {
        id: [],
        table: [],
        keyType: [
          {
            'value': 'HASH',
            'label': 'HASH'
          },
          {
            'value': 'STRING',
            'label': 'STRING'
          }
        ]
      }
    };
  },
  created() {
  	// 1.设置默认数据,也可以直接在defaultData内置数据,设置默认数据主要是服务接口下发的数据
    //	this.$set(this, 'defaultData', JSON.parse(JSON.stringify(this.taskDetailSourceData)));
    //	2.初始化时设置所需的选项数据,未必需要
    //	this.getIds();
  },
  methods: {
    // 自组件触发,用于更新表单所需选项
    updateOptions(data) {
      const { updateList, cleanList, formData } = data;
      const { optionsObj } = this;
      console.log(data);
      updateList.forEach(item => {
        if (item.target === 'table') {
          this.getTables(formData[item.source]);
        }
      });

      cleanList.forEach(item => {
        optionsObj[item].splice(0, optionsObj[item].length);
      });
    },

    getTables(value) {
      getTables({ id: value }).then(res => {
        let result = res && res.data && res.data.length > 0 ? res.data : [];
        result = result.map(item => {
          return {
            label: item,
            value: item
          };
        });
        this.optionsObj.table.splice(0, this.optionsObj.table.length, ...result);
      }).catch(e => {});
    },

    getIds() {
      getIds().then(res => {
        if (res && res.data && res.data.length > 0) {
          this.optionsObj.id.push(...res.data.map(item => {
            return {
              label: item.name,
              value: item.id
            };
          }));
        }
      }).catch(e => {});
    },

    submitForm(data) {
      this.$emit('submitData', { type: 'input', data });
    },

    submit() {
      //  调子组件方法实现
      this.$refs['customForm'].submitForm();
    }
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值