温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2022-07-29 14:51:18 来源:亿速云 阅读:236 作者:iii 栏目:开发技术

本篇内容主要讲解“vue如何封装form表单组件拒绝重复写form表单”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue如何封装form表单组件拒绝重复写form表单”吧!

    核心思想:

    • 通过配置js文件的变量,使用vueis属性动态切换组件,默认显示的组件为el-input

    • 通过element的分栏和栅格属性,对form表单进行响应式布局

    • baseForm在组件初始化时,需要动态添加校验规则请求接口以及初始化form的部分值

    • 正统思想是对element组件的各个组件进行二次封装,然后通过is属性切换二次封装后的组件,在此不做过多描述,有兴趣的朋友可以自行研究

    • 更好的思想是将页面请求、搜索项、表格、分页封装到一起,形成一个整体,这也是我们前端小组目前的处理思路

    实现重点:

    • 任何标签或者组件都可以通过vue的is属性来动态切换组件。本组件中使用div,将它的宽度设置为100%,使得element组件能够完全撑开。(使用vue内置组件component会与el-radio-group相冲突,因为它底层就是用component实现的)

    • 表单上添加validate-on-rule-change="false"属性,防止在表单初始化时就校验表单

    • 当为对象添加不存在的字段属性时,需要使用$set实现数据的响应式

    • 如果form表单中只有一个输入框,在输入框中按下回车会提交表单,刷新页面。为了阻止这一默认行为,需要在el-form标签上添加@submit.native.prevent

    • 使用lodash中的get方法获取对象的属性值,如果属性值不存在,可以给一个默认值

    • baseForm子组件中可以传一个form对象给父组件,那么添加或者编辑form对象,就都可以在父组件中进行。

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

    1.使用v-model进行双向绑定
    <div
      v-else
      clearable
      
      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
      
      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数组中每一个对象对应的字段(非请求接口):

    • label (表单label的名称)

    • span (这个表单项占据的份数,一行为24,默认为12)

    • labelWidth (这个表单项的label宽度,默认为90px)

    • labelHeight (这个表单项占据的高度,默认为50px)

    • slotName (插槽名)

    • prop (这个表单项绑定的属性名称)

    • size (这个表单项组件的大小,默认为small)

    • disabled (是否禁用这个表单项)

    • type (使用的element组件,默认为el-input)

    • dic (非接口请求的静态表单数据,使用{label以及value字段}表示的数组形式)

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

    • url (接口的api地址)

    • requestParams (非必填项,需要额外传入的传参)

    • requestLabel (接口返回对应的id)

    • requestValue (接口返回对应的value)

    效果浏览

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

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

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

    源码放送

    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
                
                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. 添加或编辑

    • 添加: 如果是添加状态,直接在父组件中引入就好。在点击确定按钮时,拿到子组件的ref并进行表单校验。校验通过后,使用后端定义好的接口进行传参;

    • 编辑: 如果是编辑状态,则需要在父组件页面初始化时,将后端返回的数据使用$set进行初始赋值,其余操作同添加状态。

    到此,相信大家对“vue如何封装form表单组件拒绝重复写form表单”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI