vue2.x简单二次封装el-form,实现动态添加表单和校验规则

简单封装el-form实现动态添加表单,和表单校验

操作方式

全部代码

目录结构

vue2.x简单二次封装el-form,实现动态添加表单和校验规则_第1张图片

使用

	<template>
		<div class="form">
	          <yu-form
	            ref="yuForm"
	            :basic-purchase-desc="basicPurchaseDesc"
	            :purchasing-information="purchasingInformation"
	            :is-show-add-btn="true"
	            @removeInquiry="removeInquiry"
	            @addInquiry="addInquiry"
	          />
         	 <el-button @click="next">提交</el-button>
          </div>
    </template>
       
          <script>
              import YuForm from './components/yuForm'
	          import {
		          basicPurchaseDesc, 
		          purchasingInformation,
		          addStockOrder
	          } from './helper'
				export default {
					components: {
					    YuForm
					  },
					  data() {
					    return {
					      basicPurchaseDesc: basicPurchaseDesc(), // elm基础表单描述
					      purchasingInformation: purchasingInformation() // 采购表单信息数据
					    }
					  },
					  methods: {
					  // 调用ele-form内部校验,和封装yu-form表单校验
					    next() {
					      // 校验采购表单
					      this.$refs.yuForm.validate((valid) => {
					        // 校验eleForm表单
					        if (valid) {
					          console.log(this.purchasingInformation)
					        }
					      })
					    },
					  //   添加操作
					    addInquiry() {
					      // 添加表单
					      this.purchasingInformation.push({
					        material: '', // 物料名称
					        brand: '', // 品牌
					        specification: '', // 规格/型号
					        amount: '', // 采购量
					        unit: '', // 单位
					        remark: '' // 备注
					      })
					      // 向采购中添加描述渲染另一个表单
					      this.basicPurchaseDesc.push(addStockOrder())
					    },
					  	// 删除操作
					    removeInquiry(formIndex) {
					      // 判断数据是否有多条
					      if (this.purchasingInformation.length > 1) {
					        // 把基础数据中的purchasingInformation的数组当前下标删除
					        this.purchasingInformation.splice(formIndex, 1)
					        // 向采购中删除当前下标描述
					        this.basicPurchaseDesc.splice(formIndex, 1)
					        this.$message({
					          message: '删除成功',
					          type: 'success'
					        })
					      } else {
					        this.$message({
					          message: '只剩一条了',
					          type: 'error'
					        })
					      }
					    }
					  }
				}
		  </script>

引入的./hepler.js文件


// yu-form添加采购表单字段
const addStockOrder = () => {
  return {
    material: {
      type: 'input',
      field: 'material',
      label: '物料名称',
      rules: { required: true, message: '请输入物料信息', trigger: 'blur' }
    },
    brand: {
      type: 'input',
      field: 'brand',
      label: '品牌',
      rules: { required: true, message: '请输入品牌', trigger: 'blur' }
    },
    specification: {
      type: 'input',
      field: 'specification',
      label: '规格/型号',
      rules: { required: true, message: '请输入规格型号', trigger: 'blur' }
    },
    amount: {
      type: 'input',
      field: 'amount',
      label: '采购量',
      rules: { required: true, message: '请输入采购量', trigger: 'blur' }
    },
    unit: {
      type: 'select',
      field: 'unit',
      label: '单位',
      rules: { required: true, message: '请选择单位', trigger: 'change' },
      options: [
        {
          label: '吨',
          value: 0
        },
        {
          label: '米',
          value: 1
        },
        {
          label: '件',
          value: 2
        }
      ]
    },
    remark: {
      type: 'input',
      label: '备注'
    }
  }
}

// 采购表单数据
const purchasingInformation = () => {
  return [ // 采购信息
    {
      material: '', // 物料名称
      brand: '', // 品牌
      specification: '', // 规格/型号
      amount: '', // 采购量
      unit: '', // 单位
      remark: '' // 备注
    }
  ]
}
// 基础采购描述
const basicPurchaseDesc = () => {
  return [{
    material: {
      type: 'input',
      field: 'material',
      label: '物料名称',
      rules: { required: true, message: '请输入物料信息', trigger: 'blur' }
    },
    brand: {
      type: 'input',
      field: 'brand',
      label: '品牌',
      rules: { required: true, message: '请输入品牌', trigger: 'blur' }
    },
    specification: {
      type: 'input',
      field: 'specification',
      label: '规格/型号',
      rules: { required: true, message: '请输入规格型号', trigger: 'blur' }
    },
    amount: {
      type: 'input',
      field: 'amount',
      label: '采购量',
      rules: { required: true, message: '请输入采购量', trigger: 'blur' }
    },
    unit: {
      type: 'select',
      field: 'unit',
      label: '单位',
      rules: { required: true, message: '请选择单位', trigger: 'change' },
      options: [
        {
          label: '吨',
          value: 0
        },
        {
          label: '米',
          value: 1
        },
        {
          label: '件',
          value: 2
        }
      ]
    },
    remark: {
      type: 'input',
      label: '备注'
    }
  }]
}

export {
  basicPurchaseDesc,
  addStockOrder,
  purchasingInformation
}

yuForm封装的组件

<template>
  <div class="yu-form">
    <div class="add-inquiry-btn">
      <el-button v-if="isShowAddBtn" @click="addInquiry">添加询价单</el-button>
    </div>
    <transition-group class="content" tag="form" name="fade-list">
      <el-form
        v-for="(formInfo, formIndex) in basicPurchaseDesc"
        ref="rulesForm"
        :key="formIndex"
        :inline="true"
        :model="purchasingInformation[formIndex]"
        label-position="top"
      >
        <el-form-item
          v-for="(info, infoIndex) in formInfo"
          :key="info.field"
          :label="info.label"
          :prop="infoIndex"
          :rules="info.rules"
        >
          <el-input
            v-if="info.type === 'input'"
            v-model="purchasingInformation[formIndex][infoIndex]"
            :placeholder="'请输入'+info.label"
          />
          <el-select
            v-else
            v-model="purchasingInformation[formIndex][infoIndex]"
            :placeholder="'请选择'+info.label"
          >
            <el-option
              v-for="option in info.options"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item class="delete">
          <el-button type="danger" @click="removeInquiry(formIndex)">删除</el-button>
        </el-form-item>
      </el-form>
    </transition-group>
  </div>
</template>

<script>
// 对el-form二次封装
export default {
  name: 'YuForm',
  props: {
    // 多组校验
    basicPurchaseRules: {
      type: Array,
      default() {
        return []
      }
    },
    // 基础信息描述
    basicPurchaseDesc: {
      type: Array,
      default() {
        return []
      }
    },
    // 基础数据
    purchasingInformation: {
      type: Array,
      default() {
        return {}
      }
    },
    isShowAddBtn: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      isValidate: null
    }
  },
  methods: {
    // 删除对应表单
    removeInquiry(formIndex) {
      this.$emit('removeInquiry', formIndex)
    },
    // 校验表单
    validate(cb) {
      this.isValidate = null
      this.purchasingInformation.forEach((item, index) => {
        this.$refs['rulesForm'][index].validate((valid) => {
          this.isValidate += valid
          if (this.purchasingInformation.length === this.isValidate) {
            cb(valid)
          }
        })
      })
    },
    // 添加询价单
    addInquiry() {
      this.$emit('addInquiry')
    }
  }
}
</script>

<style scoped lang="scss">
.add-inquiry-btn {
  margin: 20px 0;
}
.delete {
  margin: 0;
  ::v-deep .el-form-item__content {
    height: 125px;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
  }
}
.fade-list-enter-active {
  opacity: 0;
  transform: translateY(100%);
  transition: all .6s;
}
.fade-list-enter-to {
  opacity: 1;
  transform: translateY(0);
}
.fade-list-leave-to {
  opacity: 0;
  transform: translateY(0);
  transition: all .6s;
}
</style>

介绍

  • 共有两个组件一个父组件,一个子组件,父组件中使用子组件中封装
    • 父组件名称setp.vue,子组件yuForm.vue

下面是子组件yuForm.vue

  • class=“add-inquiry-btn”,这个类名的标签是一个添加数据的form表单的标签,用来操作表单数据的
  • el-form外层包裹了一层transition-group这个作用是用来让添加的数据有动画这个要配合样式使用

如何做到动态渲染的

  • 首先对el-form使用v-for指令对basicPurchaseDesc数组进行循环,这个basicPurchaseDesc中的数据格式我会放在下方,这下方的这个格式是个数组对象,默认只有一条数据,当使用v-for对其循环时,会渲染出一个表单。我们再看内层的el-form-item,这里也是使用v-for对el-form遍历的之后的数据在进行遍历,(v-for不仅仅可以遍历数组也遍历对象,遍历对象的时候第一个值是返回的当前对象第二个值就是当前对象的键),遍历之后可以通过type来判断是input还是select(我这里之处理了两种),这里的数据包括了校验规则。

    // 表单描述信息
     [{
    material: {
      type: 'input',
      field: 'material',
      label: '物料名称',
      rules: { required: true, message: '请输入物料信息', trigger: 'blur' }
    },
    brand: {
      type: 'input',
      field: 'brand',
      label: '品牌',
      rules: { required: true, message: '请输入品牌', trigger: 'blur' }
    },
    specification: {
      type: 'input',
      field: 'specification',
      label: '规格/型号',
      rules: { required: true, message: '请输入规格型号', trigger: 'blur' }
    },
    amount: {
      type: 'input',
      field: 'amount',
      label: '采购量',
      rules: { required: true, message: '请输入采购量', trigger: 'blur' }
    },
    unit: {
      type: 'select',
      field: 'unit',
      label: '单位',
      rules: { required: true, message: '请选择单位', trigger: 'change' },
      options: [
        {
          label: '吨',
          value: 0
        },
        {
          label: '米',
          value: 1
        },
        {
          label: '件',
          value: 2
        }
      ]
    },
    remark: {
      type: 'input',
      label: '备注'
    }
    }]
    
  • 在下面就是说purchasingInformation这个保存数据的问题,这个数据也是一个数组对象格式的,el-form和el-form-item中的mode就是绑定这个数据el-form通过遍历的返回的formIndex下标

    
     <el-form
            v-for="(formInfo, formIndex) in basicPurchaseDesc"
            ref="rulesForm"
            :key="formIndex"
            :inline="true"
            :model="purchasingInformation[formIndex]"
            label-position="top"
          >el-form>
      
     // purchasingInformation数组内容
    [ // 采购信息
        {
          material: '', // 物料名称
          brand: '', // 品牌
          specification: '', // 规格/型号
          amount: '', // 采购量
          unit: '', // 单位
          remark: '' // 备注
        }
      ]
    
    • 这个是el-form-item绑定数据和表单校验问题
    
    		<el-form-item
              v-for="(info, infoIndex) in formInfo"
              :key="infoIndex"
              :label="info.label"
              :prop="infoIndex"
              :rules="info.rules"
            >
              <el-input
                v-if="info.type === 'input'"
                v-model="purchasingInformation[formIndex][infoIndex]"
                :placeholder="'请输入'+info.label"
              />
              <el-select
                v-else
                v-model="purchasingInformation[formIndex][infoIndex]"
                :placeholder="'请选择'+info.label"
              >
                <el-option
                  v-for="option in info.options"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                />
              el-select>
            el-form-item>
            <el-form-item class="delete">
              <el-button type="danger" @click="removeInquiry(formIndex)">删除el-button>
            el-form-item>
    
  • 下面这些是逻辑这块的yuForm.vue

<script>
// 对el-form二次封装
export default {
  name: 'YuForm',
  // 这里的数据是接收父组件传递的数据
  props: {
    // 基础信息描述
    basicPurchaseDesc: {
      type: Array,
      default() {
        return []
      }
    },
    // 基础数据
    purchasingInformation: {
      type: Array,
      default() {
        return {}
      }
    },
    // 是否显示添加按钮
    isShowAddBtn: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      isValidate: null
    }
  },
  methods: {
    // 删除对应表单
    removeInquiry(formIndex) {
      this.$emit('removeInquiry', formIndex)
    },
    // 校验表单
    validate(cb) {
      this.isValidate = null
      // 由于有多个表单需要进行校验所以直接遍历数据让来校验是否有没有填写的字段
      this.purchasingInformation.forEach((item, index) => {
        this.$refs['rulesForm'][index].validate((valid) => {
        // vaild这个返回的数据如果当前index下标的表单有校验字段的内容为空就会返回false反之true,
        // 这里通过这个来进行累加判断如果返回的有一个是false都是校验不通过
          this.isValidate += valid
          if (this.purchasingInformation.length === this.isValidate) {
          // 如果都是所有的字段都填写了这时候通过校验callback返回给父组件处理
            cb(valid)
          }
        })
      })
    },
    // 添加询价单
    addInquiry() {
      this.$emit('addInquiry')
    }
  }
}
</script>

父组件中

<template>

		<div class="form">
	          <yu-form
	            ref="yuForm"
	            :basic-purchase-desc="basicPurchaseDesc"
	            :purchasing-information="purchasingInformation"
	            :is-show-add-btn="true"
	            @removeInquiry="removeInquiry"
	            @addInquiry="addInquiry"
	          />
         	 <el-button @click="next">提交el-button>
          div>
    template>
       
          <script>
          	  //  使用封装的组件
              import YuForm from './components/yuForm'
              // 从./hepler.js导出所需要的数据
	          import {
		          basicPurchaseDesc, 
		          purchasingInformation,
		          addStockOrder
	          } from './helper'
				export default {
					components: {
					    YuForm
					  },
					  data() {
					    return {
					      basicPurchaseDesc: basicPurchaseDesc(), // elm基础表单描述
					      purchasingInformation: purchasingInformation() // 采购表单信息数据
					    }
					  },
					  methods: {
					  // 调用ele-form内部校验,和封装yu-form表单校验
					    next() {
					      // 校验采购表单
					      this.$refs.yuForm.validate((valid) => {
					        // 校验eleForm表单
					        if (valid) {
					          console.log(this.purchasingInformation)
					        }
					      })
					    },
					  //   添加操作
					    addInquiry() {
					      // 添加表单
					      this.purchasingInformation.push({
					        material: '', // 物料名称
					        brand: '', // 品牌
					        specification: '', // 规格/型号
					        amount: '', // 采购量
					        unit: '', // 单位
					        remark: '' // 备注
					      })
					      // 向采购中添加描述渲染另一个表单
					      this.basicPurchaseDesc.push(addStockOrder())
					    },
					  	// 删除操作
					    removeInquiry(formIndex) {
					      // 判断数据是否有多条
					      if (this.purchasingInformation.length > 1) {
					        // 把基础数据中的purchasingInformation的数组当前下标删除
					        this.purchasingInformation.splice(formIndex, 1)
					        // 向采购中删除当前下标描述
					        this.basicPurchaseDesc.splice(formIndex, 1)
					        this.$message({
					          message: '删除成功',
					          type: 'success'
					        })
					      } else {
					        this.$message({
					          message: '只剩一条了',
					          type: 'error'
					        })
					      }
					    }
					  }
				}
		  script>

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