vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue封装form表单组件

vue封装form表单组件拒绝重复写form表单

作者:前端贰货道士

这篇文章主要为大家介绍了vue封装form表单组件拒绝重复写form表单的实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

在日常工作中,当需要处理的form表单很多时,我们没有必要一遍又一遍地重复写form表单,直接封装一个组件去处理就好。其实很早之前就有涉猎通过使用类似配置json方法写form表单的文章,虽然当时也没怎么认真看...我们前端组也是使用这种思想配置的。

然而,这个思想和方法很早就有出现过,并不怎么新颖,还望不喜勿喷...在此我封装了一个最最最基础的form表单,离我们前端组封装的组件差距还很大,有兴趣朋友们的可以继续往下完善。

核心思想:

实现重点:

表单双向绑定的方式有两种: 

1.使用v-model进行双向绑定

<div
  v-else
  clearable
  style="width: 100%"
  type="daterange"
  range-separator="至"
  start-placeholder="开始日期"
  end-placeholder="结束日期"
  v-model="form[column.prop]"
  :label-width="get(column, 'size', column || defaultFormSize)"
  :disabled="get(column, 'disabled', false)"
  :is="get(column, 'type', 'el-input')"
>

2.使用v-model的语法糖

(`:value以及@input`)进行双向绑定

<div
  v-else
  clearable
  style="width: 100%"
  type="daterange"
  range-separator="至"
  start-placeholder="开始日期"
  end-placeholder="结束日期"
  :value="form[column.prop]"
  :label-width="get(column, 'size', column || defaultFormSize)"
  :disabled="get(column, 'disabled', false)"
  :is="get(column, 'type', 'el-input')"
  @input="input($event,column.prop)"
>
methods: {
    input(e,prop) {
      this.$set(this.form, prop, e)
    }
}

配置项

(本组件写得比较基础,目前仅支持element的五个常用组件):

整体字段:

formSize (表单中各element组件的整体大小)

column数组中每一个对象对应的字段(非请求接口):

column数组中每一个对象对应的字段(请求接口):

效果浏览

源码放送

1. baseForm组件

<template>
  <el-form
    ref="form"
    :model="form"
    :rules="formRules"
    :size="get(option, 'formSize', defaultFormSize)"
    :validate-on-rule-change="false"
    @submit.native.prevent
  >
    <el-row :gutter="20" :span="24">
      <el-col 
        v-for="column in formColumn" 
        :key="column.label" 
        :md="column.span || 12" 
        :sm="12" 
        :xs="24"
      >
        <el-form-item
          :label="`${column.label}:`"
          :prop="column.prop"
          :label-width="get(column, 'labelWidth', column.labelWidth || defaultLabelWidth)"
          :style="{
            height: get(column, 'labelHeight', column.labelHeight || defaultLabelHeight)
          }"
        >
          <slot
            v-if="column.slotName"
            :name="column.slotName"
            :form="form"
            :prop="column.prop"
            :value="form[column.prop]"
          ></slot>
          <div
            v-else
            clearable
            style="width: 100%"
            type="daterange"
            range-separator="-"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            v-model="form[column.prop]"
            :placeholder="getPlaceholder(column.type, column.label)"
            :label-width="get(column, 'size', column || defaultFormSize)"
            :disabled="get(column, 'disabled', false)"
            :is="get(column, 'type', 'el-input')"
          >
            <template v-if="column.type == 'el-select'">
              <el-option 
                v-for="item in column.dic" 
                :key="item.value" 
                :label="item.label" 
                :value="item.value"
              >
              </el-option>
            </template>
            <template v-if="column.type == 'el-radio-group'">
              <el-radio 
                v-for="item in column.dic" 
                :key="item.value" 
                :label="item.label"
              >
                {{ item.value }}
              </el-radio>
            </template>
            <template v-if="column.type == 'el-checkbox-group'">
              <el-checkbox 
                v-for="item in column.dic" 
                :key="item.label" 
                :label="item.value"
              >
                {{ item.label }}
              </el-checkbox>
            </template>
          </div>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script>
import get from 'lodash/get'
import request from '@/service/request'
export default {
  props: {
    option: {
      type: Object,
      default: () => {}
    },
    form: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      formRules: {},
      defaultFormSize: 'small',
      defaultLabelWidth: '90px',
      defaultLabelHeight: '50px'
    }
  },
  computed: {
    formColumn() {
      return this.option.column
    }
  },
  created() {
    this.initRules()
    this.initRequest()
    this.initValue()
  },
  methods: {
    get,
    getPlaceholder(type, label) {
      return type == 'el-select' ? `请选择${label}` : `请输入${label}`
    },
    initRequest() {
      if (!Array.isArray(this.formColumn)) return
      // 根据实际请求接口地址的前缀来判断
      const urls = this.formColumn?.filter((item) => item.url && item.url.indexOf('/emes') == 0) || []
      urls.forEach(async (item) => {
        const data = { page: { pageIndex: 1, pageSize: 0 }, ...item.requestParams }
        const { detail } = await request({
          url: item.url,
          method: 'post',
          data
        }) || []
        const finalResult = detail.map((result) => ({
          label: result[item.requestLabel],
          value: result[item.requestValue]
        }))
        this.$set(item, 'dic', finalResult)
      })
    },
    initRules() {
      if (!Array.isArray(this.formColumn)) return
      this.formColumn?.forEach((item) => {
        if (item.rules) {
          item.rules.map((rule, index) => {
            if (rule.required) {
              item.rules.splice(index, 1, {
                message: ['el-radio-group', 'el-checkbox-group'].includes(item.type) ? `${item.label}必选` : `${item.label}必填`,
                ...rule
              })
            }
          })
          this.$set(this.formRules, item.prop, item.rules)
        }
      })
    },
    initValue() {
      const selectList = this.formColumn.filter((item) => ['el-radio-group', 'el-checkbox-group'].includes(item.type))
      selectList.forEach((item) => {
        this.$set(this.form, item.prop, item.type == 'el-radio-group' ? item.dic[0].label : [item.dic[0].value])
      })
    }
  }
}
</script>

2. 父组件

<template>
  <div class="app-container">
    <myForm :option="option" :form="form">
      <template #usageSlot="{form, prop}">
        <el-input 
          size="small" 
          placeholder="请输入插槽使用" 
          v-model="form[prop]" 
          clearable
        >
        </el-input>
      </template>
    </myForm>
  </div>
</template>
<script>
import { option } from './const.js'
export default {
  data() {
    return {
      option,
      form: {}
    }
  }
}
</script>

3. 配置项

export const option = {
  column: [
    {
      label: '姓名',
      prop: 'name',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '职业',
      prop: 'job',
      type: 'el-select',
      span: 8,
      dic: [
        {
          label: '教师',
          value: 0
        },
        {
          label: '程序猿',
          value: 1
        },
        {
          label: '作家',
          value: 2
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '性别',
      prop: 'sex',
      span: 8,
      type: 'el-radio-group',
      dic: [
        {
          label: 0,
          value: '男'
        },
        {
          label: 1,
          value: '女'
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '城市',
      prop: 'city',
      type: 'el-checkbox-group',
      span: 8,
      dic: [
        {
          label: '仙桃',
          value: 0
        },
        {
          label: '泉州',
          value: 1
        },
        {
          label: '武汉',
          value: 2
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '出生日期',
      prop: 'data',
      type: 'el-date-picker',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '测试',
      prop: 'test',
      type: 'el-select',
      span: 8,
      url:'/emes/factoryOrderService/warehouse/list',
      requestLabel: 'warehouseName',
      requestValue: 'id',
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '插槽使用',
      prop: 'usage',
      slotName: 'usageSlot',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    }
  ]
}

4. 添加或编辑

以上就是vue封装form表单组件拒绝重复写form表单的详细内容,更多关于vue封装form表单组件的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文