推荐你使用基于Vant-UI二次封装的数据驱动式表单自动生成组件

1,813 阅读3分钟
原文链接: mp.weixin.qq.com

关注  前端技术专栏 ,回复“  资源 ”免费领取全套视频教程 前言 在使用Vue写移动端开发的时候,难免会遇到需要写很多的表单,所以我在现在的项目里面集成了有赞的Vant-ui组件库,但是感觉Vant-ui对于表单组件的调用方式有点繁琐,实在不愿意去干这么一样的事情,就封装了一个基于Vant-ui的数据驱动式表单自动生成组件。 具体怎么玩,我们下面一起来看看吧~ 正文

组件现在的状态

  • 目前已经集成的组件如下:

    Address、Checkbox、DatePicker、Input、Radio、Select、Text、Switch、Upload

       其它组件还在完善中...

  • 组件的调用方式采取json配置的形式,具体参数见model数据说明

  • 校验规则已经集成VeeValidate插件,也可以自定义扩展规则,更多资料:  https://logaretm.github.io/vee-validate

在线演示地址: https://codesandbox.io/s/v-formshili-3hs2c?file=/src/main.js:53-383

安装

# yarnyarn add @xuanmo/v-form# npmnpm install @xuanmo/v-form -S

使用

配置

vue.config.js配置组件编译(注:如果组件引入采取的后编译需要配置这一项)

module.exports = {  transpileDependencies: [    '@xuanmo/v-form'  ]}

Props

字段名 说明 类型 默认值
v-model(value) 获取组件处理完成的数据 object {}
model 数据模型(具体类型参考后续文档) object {}
disabled 是否禁用表单 boolean false
label-width label宽度 string 20%
label-position label对齐方式,可选:left/right string left
label-color label文字颜色 string -
show-label 是否显示label boolean true

event

事件名 说明 回调参数

change

数据更改时触发

object{value,errorMsg,isValid}

event

数据发生改变所发送的事件

object{event,formModel}

slots

组件可接受多个slot,用于替换当前行的表单组件,会为该slot传入该组件的原始数据,每个slot的name为当前行的key

注:该slot不继承所有校验规则

<v-form :model="model">  <template v-slot:text="{ data }">    <van-field v-model="data.value"></van-field>  </template>  <!-- 行扩展字段slot,格式{key}-extra -->  <template #text-extra>    extra  </template></v-form>

示例

main.js中全局注册

import "@vant/touch-emulator";// 如果没有安装vant-ui可以采取这种方式引入组件import VForm from "@xuanmo/v-form/dist/v-form.umd.js";import "@xuanmo/v-form/dist/v-form.css";// 项目已经引入vant-ui推荐使用这种方式引入,后编译// import VForm from '@xuanmo/v-form'Vue.use(VForm);Vue.config.productionTip = false;new Vue({  render: h => h(App)}).$mount("#app");

页面中使用

<template>  <div id="app">    <div style="margin-bottom: 30px">      <span style="vertical-align: super;">切换表单禁用状态</span>      <van-switch v-model="disabled" size="20px" />    </div>    <v-form      ref="vform"      v-model="formValue"      :model="model"      :disabled="disabled"      label-width="100px"      @change="_change"      @event="_event"    >      <template #text1-label>        自定义label      </template>      <template #text1-extra>        <!-- <van-field v-model="data.value"></van-field> -->        extra      </template>    </v-form>    <div style="margin: 20px 0;text-align: center;">      <van-button type="primary" @click="_submit">提交数据</van-button>    </div>  </div></template><script>import { Switch, Button } from 'vant'export default {  name: 'App',  components: {    // 'van-field': Field,    'van-switch': Switch,    'van-button': Button  },  data () {    return {      formValue: {        text: 1      },      formData: {},      formError: [],      isValid: false,      disabled: false,      model: {        numberKeyboard: {          value: '',          rules: {            label: '数字键盘',            type: 'VNumberKeyboard',            placeholder: '点击输入',            // theme: 'custom',            extraKey: '.',            // closeButtonText: '完成'          }        },        file: {          value: [{ path: 'https://www.xuanmo.xin/wp-content/uploads/2019/10/xuanmo_avatar.JPG' }],          rules: {            label: '文件上传',            type: 'VUpload',            action: 'xxx',            accept: 'image/png',            multiple: true,            name: 'file',            data: {              dir: 'test'            },            props: {              url: 'path'            }          }        },        switch: {          value: true,          rules: {            label: '是否启用编辑',            type: 'VSwitch'          }        },        text: {          value: '',          rules: {            label: '文字',            type: 'VInput',            vRules: 'required|max:2',            placeholder: '请输入文字',            errorMsg: '请输入文字',            extra: 'extra'          }        },        text1: {          value: '文字内容',          rules: {            label: '文字1',            type: 'VText'          }        },        checkbox: {          value: ['a'],          rules: {            label: '复选框',            type: 'VCheckbox',            vRules: 'required',            placeholder: '请输入复选框',            errorMsg: '请输入复选框',            direction: 'horizontal',            options: [              { label: '复选框 a', value: 'a' },              { label: '复选框 b', value: 'b' },              { label: '复选框 c', value: 'c' }            ]          }        },        radio: {          value: 'b',          rules: {            label: '单选框',            type: 'VRadio',            vRules: 'required',            disabled: true,            placeholder: '请输入单选框',            errorMsg: '请输入单选框',            direction: 'horizontal',            options: [              { label: '复选框 a', value: 'a' },              { label: '复选框 b', value: 'b' },              { label: '复选框 c', value: 'c' }            ]          }        },        date: {          value: Date.now(),          rules: {            label: '时间',            type: 'VDatePicker|datetime',            valueFormat: 'timestamp'          }        },        dateRange: {          value: [Date.now(), Date.now()],          rules: {            label: '时间',            type: 'VDatePickerRange|time',            valueFormat: 'timestamp',            rangeSeparator: '至'          }        },        number: {          value: '',          rules: {            label: '数字',            type: 'VInput|digit',            vRules: 'required',            placeholder: '请输入数字',            errorMsg: '请输入数字'          }        },        address: {          value: '110000,110100,110114',          rules: {            label: '地址选择',            type: 'VAddress',            vRules: 'required',            placeholder: '请输入地址',            errorMsg: '请输入地址'          }        },        textarea: {          value: '',          rules: {            label: '文本域',            type: 'VInput|textarea',            vRules: 'required',            placeholder: '文本域',            errorMsg: '文本域'          }        },        select: {          value: '4',          rules: {            label: '选择器',            type: 'VSelect',            placeholder: 'picker选择器',            errorMsg: 'picker选择器',            vRules: 'required',            options: [              { text: '杭州', value: 1 },              { text: '宁波', value: 2 },              { text: '温州', value: 3 },              { text: '嘉兴', value: 4 },              { text: '湖州', value: 5 }            ]          }        },        selectMultiple: {          value: '4,2',          rules: {            label: '多列选择器',            type: 'VSelect',            placeholder: 'picker选择器',            errorMsg: 'picker选择器',            options: [              [                { text: '杭州', value: '1' },                { text: '宁波', value: '2' },                { text: '温州', value: '3' },                { text: '嘉兴', value: '4' },                { text: '湖州', value: '5' }              ],              [                { text: '杭州', value: '1' },                { text: '宁波', value: '2' },                { text: '温州', value: '3' },                { text: '嘉兴', value: '4' },                { text: '湖州', value: '5' }              ]            ]          }        }      }    }  },  methods: {    _change ({ value, errorMsg, isValid }) {      this.formData = value      this.formError = errorMsg      this.isValid = isValid    },    _event ({ type, value }) {      console.log(type, value)    },    _submit () {      if (!this.isValid) {        this.$toast(this.formError[0].errorMsg)        return      }      this.$toast('提交成功')    }  }}</script><style>#app {  font-size: 14px;}</style>
最终效果

结语

说实话,自从封了这个组件就感觉对于表单的处理就只是一串数据而已,其它的基本不用管,最后直接取填完表单后的数据就可以了,减少了不少繁琐,不用到处复制粘贴,还可以自己去更好的扩展自己想要的功能。如果各位同学表示认同,可以去我的Github帮点个Star,表示支持吧~

仓库地址:

https://github.com/xuanmos/v-form 猜你爱看 手写一个符合Promise A+规范的Promise实现 一文搞懂Linux CentOS7中关于MongoDB的认证和授权设置 只需5分钟,让你了解未来可能推翻Node的新轮子 Deno 1.0

微  博:前端吴佳

QQ群:856363266


长按识别二维码

关注 「前端技术专栏」加星标

每天给您推送最新原创技术文章

好看,帮点击 在看❤️