Bootstrap

基于vant封装的动态表单(VFrom使用教程)

vant-ui是属于vue开发移动端中用的比较多的一个组件库了,网上基于它的一些组件的二次封装也数不胜数,但是却都是零零散散,不成体系。总不能用一个就去找类似的封装吧,这样拼凑起来的也不是我们想要的。尤其,涉及众多表单业务的时候。

1.场景需求 

假如你遇到这样一个场景,需要做一个表单收集。涉及到输入框,单选框,多选框,下拉框,时间选择等等七八个表单。基于vant-ui的情况下,去官网单个的去复制粘贴。就这样一个vue页面是不是起码就几百行了。这还不算假如是在一个tabs标签页下,每个标签页下都有七八个表单呢?

这个时候,阁下又该如何自处?组件化,那就多少个标签多少个组件。不利于维护。改起来也麻烦。写一个页面?哪起码上千行代码了。

先看下效果图,有个最直观的感受:

所以,当涉及多个表单时,我们就迫切的需要一个成体系化的二次封装表单。

2.vform使用说明

v-form: 🎉 基于Vant-UI进行二次封装动态生成表单,也可完全自定义控件,通过 JSON 的形式配置,内部集成繁琐的校验规则,可扩展的校验

文档有详细说明。照猫画虎对于一些动手能力强的人来说那就是手拿把掐。这里我也就不多加叙述了。

 3.从无到有

        文档上说的很清楚,也不得不承认它的封装的却是很好。不多相比于大多数业务场景而言,也用不到那么复制。就一个最常见的场景来说。生成表单,收集信息 这八个字就是我们的核心思想,迫切所需要的。

闲话少叙,跟随lz的脚步,我们一起实操下:

1.引入依赖,全局注册

 man.js

// 注册封装表单:https://gitee.com/cgb-lowcode/v-form
import VForm from '@xuanmo/v-form'
import '@xuanmo/v-form/packages/style/index.less'



Vue.use(VForm);
// 设置防抖时间,默认200ms
Vue.use(VForm, {
  debounceTime: 200
})

tips:项目技术栈是vue+vant。记得提前引入vant。

2.模拟动态表单数据

formModel.js

const formdata =  {
    family:[        
        { rules: { type: "VCell" } },
        {
            key:'text1',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text2',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text3',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text4',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text5',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text6',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text7',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        { rules: { type: "VCell" } },
        {
            key:'text8',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text9',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text10',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        { rules: { type: "VCell" } },
        {
            key:'text11',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text12',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text13',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text14',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text15',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        }
    ],
    health:[        
        { rules: { type: "VCell" } },
        {
            key:'text1',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text2',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text3',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text4',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
    ],
    children:[        
        { rules: { type: "VCell" } },
        {
            key:'text1',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text2',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text3',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text4',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        { rules: { type: "VCell" } },
        {
            key:'text5',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text6',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
    ],
    retire:[     
        { rules: { type: "VCell" } },
        {
            key:'text1',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text2',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text3',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text4',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text5',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text6',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        { rules: { type: "VCell" } },
        {
            key:'text7',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text8',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text9',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
    ],
    riches:[        
        { rules: { type: "VCell" } },
        {
            key:'text1',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra',
            }
        },
        {
            key:'text2',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text3',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text4',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        },
        {
            key:'text5',    
            value: '',
            rules: {
                label: '文本',
                type: 'VInput',
                vRules: 'required',
                placeholder: '请输入',
                errorMsg: '请输入',
                extra: 'extra'
            }
        }
    ]


}
export default formdata;

3.vue页面使用

<template>
  <div class='dataedit'>
    <van-nav-bar
      title='数据收集'
      left-arrow
      @click-left='$router.back()'
    ></van-nav-bar>
    <div class="main">
        <van-tabs @disabled="onClickDisabled" @change="changeTab" v-model.number="active" sticky color="#FF6837" title-active-color="#FF6837" line-width="0.5rem">
          <van-tab disabled>
            <template #title><img src="@/assets/menu/11.png" alt="" style="width:0.8rem;height:0.8rem;margin-top:0.2rem"></template>
          </van-tab>
          <van-tab title="表单1">
              <v-form
                ref="vform"
                v-model="formValue.family"
                :model="model.family"
                :disabled="disabled"
                label-width="80%"
                :label-color="labelColor"
                @change="change"
              >
              </v-form>
          </van-tab>
          <van-tab title="表单2">
            <v-form
                ref="vform"
                v-model="formValue.health"
                :model="model.health"
                :disabled="disabled"
                label-width="80%"
                :label-color="labelColor"
                @change="change"
              >
              </v-form>
          </van-tab>
          <van-tab title="表单3">
            <v-form
                ref="vform"
                v-model="formValue.children"
                :model="model.children"
                :disabled="disabled"
                label-width="80%"
                :label-color="labelColor"
                @change="change"
              >
              </v-form>
          </van-tab>
          <van-tab title="表单4">
            <v-form
                ref="vform"
                v-model="formValue.retire"
                :model="model.retire"
                :disabled="disabled"
                label-width="80%"
                :label-color="labelColor"
                @change="change"
              >
              </v-form>
          </van-tab>
          <van-tab title="表单5">
            <v-form
                ref="vform"
                v-model="formValue.riches"
                :model="model.riches"
                :disabled="disabled"
                label-width="80%"
                :label-color="labelColor"
                @change="change"
              >
              </v-form>
          </van-tab>
        </van-tabs>
    </div>
    <div class="btn">
        <van-button round block type="info" color="#FF6837" to="/sys/data/addinfo">保存</van-button>
    </div>
  </div>
</template>

<script>
import formModel from "./formModel";
export default {
  name: 'dataedit',
  data () {
    return {
        active:1,
        model:formModel,
        disabled: false,        // 是否禁用表单
        labelColor: "inherit",  // label颜色
        formValue: {            // 表单值
          family:{},
          health:{},
          retire:{},
          children:{},
          riches:{}
        },
    }
  },
  mounted(){
    console.log("参数:",this.$route.query.id);
  },
  methods: {
    onClickDisabled(){
      console.log("点击头像");
    },
    change({ value, errorMsg, isValid }) {
      console.log("表单值:",value);
      this.formData = value;
      this.formError = errorMsg;
      this.isValid = isValid;
    },
    changeTab(val){
      console.log("当前标签===》",val);
    },
  }
}
</script>

<style lang='less' scoped>
    ::v-deep .v-form-container .v-form-row{
        min-height: 1.5rem;
        padding-top: 0.25rem;
    }
    .main{
      ::v-deep .van-tab__pane{
        height: 80vh;
        overflow-y: auto;
        padding-bottom: 1rem;
      }
    }
    .btn{
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: 1.6rem;
        display: flex;
        justify-content: center;
        align-items: center;
        background: #ffffff;
        padding: 0 5%;
    }
</style>

4.最终效果图

 数据是实时获取的。formModel.js定义的key值就是键。type为表单类型,如VInput,VRadio,VSelect等常用表单,label就是label文本,vRules是验证规则,placeholder是原生的placeholder,errorMsg就是验证失败提示。

其他的请自行查看文档。

;