前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >写表单你还在复制粘贴吗?推荐你使用基于Vant-UI二次封装的数据驱动式表单自动生成组件

写表单你还在复制粘贴吗?推荐你使用基于Vant-UI二次封装的数据驱动式表单自动生成组件

作者头像
用户2231227
发布2022-09-26 11:05:29
1.8K0
发布2022-09-26 11:05:29
举报
文章被收录于专栏:前端技术专栏-吴佳

前言

在使用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

安装

代码语言:javascript
复制
# yarn
yarn add @xuanmo/v-form
# npm
npm install @xuanmo/v-form -S

使用

配置

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

代码语言:javascript
复制
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不继承所有校验规则

代码语言:javascript
复制
<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中全局注册

代码语言:javascript
复制
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");

页面中使用

代码语言:javascript
复制
<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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端技术专栏 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档