在vue中怎么抽取封装一个自定义表单?(学习记录)

在vue中怎么封装一个自定义表单?

最近在学习一个开源小项目时,写完了一个添加歌手的表单之后,发现代码非常的混乱。让我越看越不爽,于是就将其中的一些东西进行了封装……
目前也是通过这个小项目进行Vue的学习,边看官方文档和各种资料边学边写,觉得特别痛苦,但学了快一年了还没个完整的项目,所以只能硬着头皮边学边用了。如果有使用错误的地方,麻烦各位老哥指出
本文使用到vue+elementui

先上个效果图
在这里插入图片描述

其实本人也不熟悉Vue和elementui,我只是一个java小白。我最初封装这个表单就不过是想抽取公共部分实现复用……

这次的封装也是看了https://www.cnblogs.com/qdhxhz/p/12649759.html这位老哥的文章,根据他提供的例子所写


代码部分:
为了方便白嫖,下面的内容可直接copy

type:决定生成的标签,由父组件传入
model:双向绑定属性,由父组件传入
label:标签所对应的数据,由父组件传入

<div>
    <el-form :rules="rule" :model="form" ref="form" label-width="80px">

        <el-form-item v-for="item in labelAndType"
                      :key="item.model" :label="item.label"
                      :prop="item.model">
          <!--根据type生成对应的标签-->
          <el-input v-model="form[item.model]"
                    :placeholder="'请输入'+item.label"
                    v-if="item.type==='input'"></el-input>
          <!--select标签-->
          <el-select v-model="form[item.model]"
                     :placeholder="'请输入'+item.label"
                     v-if="item.type==='select'">
            <el-option v-for="opt in item.option"
                       :key="opt.value"
                       :label="opt.label"
                       :value="opt.value">

            </el-option>
          </el-select>
          <!--单选框-->
          <el-radio-group v-model="form[item.model]" v-if="item.type==='radio'">
            <el-radio-button v-for="opt in item.option"
                             :key="opt.value"
                             :label="opt.label"
                             border>{{opt.value}}</el-radio-button>
          </el-radio-group>
          <!--switch-->
          <el-switch v-model="form[item.model]"
                     v-if="item.type==='switch'">

          </el-switch>
          <!--el-date-picker-->
          <el-date-picker v-model="form[item.model]"
                          type="date" v-if="item.type==='date'"
                          value-format="yyyy-MM-dd">
          </el-date-picker>
          <!--textarea输入框-->
          <el-input v-model="form[item.model]"
                    type="textarea"
                    v-if="item.type==='textarea'"
                    :placeholder="'请输入'+item.label"
                    :autosize="{minRows:item.min,maxRows:item.max}">

          </el-input>
        </el-form-item>
      <!--预留一个插槽-->
      <el-form-item>
        <slot></slot>
      </el-form-item>
    </el-form>
    <div style="padding-left: 80px">
      <el-button type="primary" style="margin-bottom: 30px" @click="selfSubmit">提交</el-button>
      <el-button  style="margin-bottom: 30px" @click="selfSubmit">重置</el-button>
    </div>
  </div>

<script>


export default {
  props: {
    // 表单数据
    form:Object,
    // 表单校验规则
    rule:Object,
    /**
     * 由该数组决定,表单的item
     * 传入的json数组必须要包含如下格式:
     * --------------------------输入和日期还有Switch标签------------------------------
     *      [
     *        {
     *          model:?   双向绑定的变量名
     *          label:?   label的值
     *          type:?    决定当前的表单将会渲染什么标签
     *        }
     *      ]
     *
     *  -----------------下面是select和radio还有CheckBox标签的数据格式---------------------
     *
     *
     *    [
     *        {
     *          model:?   双向绑定的变量名
     *          label:?   label的值
     *          type:?    决定当前的表单将会渲染什么标签
     *          option:[
     *            {
     *              label:?
     *              value:?
     *            }
     *          ]
     *        }
     *      ]
     *
     *
     *-----------------下面是textarea类型的输入框的数据格式---------------------
     *
     *    [
     *        {
     *          model:?   双向绑定的变量名
     *          label:?   label的值
     *          type:?    决定当前的表单将会渲染什么标签
     *          min:?     其实就是autosize一样的用法
     *          max:?    同上
     *        }
     *    ]
     *
     *
     *
     */
    labelAndType:Array
  },
  methods:{
    // 数据校验
    selfSubmit () {
      this.$refs['form'].validate(validata =>{
        if (validata){
          // 给父组件返回一个值,让其根据这个值来决定是否向后台提交数据
          this.$emit("submit",true)
          // this.$message.info("子组件中的方法")
        }else {
          this.$emit("submit",false)
          // this.$message.info("子组件中的提交失败")
        }
      })
    }
  }

}
</script>

1、在这次的封装中,在父组件中,定义一个表单的数据对象传入子组件
2、在父组件中根据需要生成的标签
3、在父组件中,传入表单的校验规则
4、提交表单时,子组件进行表单校验。不论通过与否都会返回一个值给父组件,那么父组件中就可以根据这一个值来决定是否向后台提交数据


那么封装完了之后该怎么用呢?

只需要在父组件的data中传入以下数据
1、表单数据对象
2、按照组件中规定的标签数据格式传入数据即可也就是说需要什么标签就按照组件中对应的数据格式传入即可
3、传入定义好的表单数据的校验规则
4、为@submit属性,定义方法


使用示例:
<template>

    <div class="table">

      <div class="container">
        <el-button type="primary" @click="addSingerBtn">添加歌手</el-button>
      </div>

        <el-dialog  :title="formType === '添加歌手'?'添加歌手':'更新歌手信息'" :visible.sync="dialogFormVisible">
            <self_form ref="form" :rule="rule" :form="addSinger" :label-and-type="formLabel" @submit="handleAddSubmit">
            </self_form>
        </el-dialog>

      </div>
</template>
<script>


import self_form from '../components/SingerForm'
import {postAddSinger,getSingerInfoAll} from '../api/index.js'
import {validataAge, validataName, validataZh} from "../utils/validator";

export default {
  components:{
    self_form
  },
  data () {
    return {
      // 表单标题
      formType:'',
      // 添加歌手弹出框默认关闭
      dialogFormVisible: false,

      // 表单数据对象
      addSinger: {
        name: '',
        age: '',
        sex: '1',
        birth: '',
        nation: '',
        info: '',
        active: true,
        category: ''
      },


      // 选择需要的表单项
      formLabel: [
        {
          model:'name',
          label:'姓名',
          type:'input'
        },
        {
          model:'age',
          label:'年龄',
          type:'input'
        },
        {
          model:'sex',
          label:'性别',
          type:'radio',
          option:[
            {
              label:'男',
              value:'男'
            },
            {
              label:'女',
              value:'女'
            }
          ]
        },
        {
          model:'birth',
          label:'日期',
          type:'date'
        },
        {
          model:'nation',
          label:'国籍',
          type:'input'
        },
        {
          model:'info',
          label:'简介',
          type:'textarea',
          min:3,
          max:6
        },
        {
          model:'active',
          label:'是否激活',
          type:'switch'
        },
        {
          model:'category',
          label:'分类',
          type:'select',
          option:[
            {
              label:"华语歌手",
              value:"华语歌手"
            },
            {
              label:"日语歌手",
              value:"日语歌手"
            },
            {
              label:"韩语歌手",
              value:"韩语歌手"
            },
          ]
        }

      ],

      // 定义表单数据校验规则
      rule: {
        name: [
          {required: true, message: '姓名不能为空', trigger: 'blur'},
          {type:'string',min:2,message: '最少输入两位字符'},
          {validator:validataName}
        ],
        age: [
          {required: true, message: '年龄不能为空', trigger: 'blur'},
          {type:'string',min:1,message: '最少输入一位数字'},
          {validator:validataAge}
        ],
        nation: [
          {required: true, message: '国籍不能为空', trigger: 'blur'},
          {type:'string',min:2,message: '最少输入两位字符'},
          {validator:validataZh}
        ],
        category:[
          {required: true, message: '分类不能为空', trigger: 'blur'}
        ],
        birth: [
          {required: true, message: '日期不能为空', trigger: 'blur'}
        ],
        info: [
          {required: true, message: '简介不能为空', trigger: 'blur'},
          {validator:[validataZh]}
        ]
      },


    }
  },
  methods:{
    addSingerBtn(){
        this.formType='添加歌手'
        this.dialogFormVisible=true
    },
    handleAddSubmit(flag){
      console.log(flag);
      if (flag){
        postAddSinger(this.addSinger).then(resp =>{
          this.$message.success('上传成功')
          console.log(resp)
        }).catch(resp =>{
          this.$message.error('上传失败')
          console.log(resp)
        })
      }else {
        console.log("父组件中的方法")
      }

    }
  }
}
</script>
<style scoped>


</style>

这个抽取出来的表单这样虽然不知道其复用性,但起码让我看起来舒服了一点点。欢迎各位大佬指出其中的不足点,最好给个解决的方法,哈哈哈哈


每天进步一点点,即使再小也算进步,加油!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值