form表单封装

封装el-form

  • 目前在编写项目中,每个页面都有el-from,所以对el-form做了二次封装, 组件在个人开发使用不错,但不确定能满足各种业务需求,所以这里主要和大家分享一下设计思路。用一次爽一次,越用越爽。
分析问题:
  • el-form是element-ui库的表单组件,如果我们要将其进行二次封装,那么需要考虑几个问题:
  • 如何设计表单渲染字段
  • 不同类型的el-form-item怎么去渲染,比如input,select,或者自定义显示内容等
  • 表单联动怎么去处理
  • 事件绑定
  • 表单验证
  • 等等.
拿表单来举例,在这个表单中的需求分析。

正常情况下,我们使用form,它的子项会是这样的,比如有input和select:

// input类型
<el-form-item label="活动名称" prop="name">
  <el-input v-model="ruleForm.name"></el-input>
</el-form-item>

// select类型
<el-form-item label="活动区域" prop="region">
  <el-select v-model="ruleForm.region" placeholder="请选择活动区域">
    <el-option label="区域一" value="shanghai"></el-option>
    <el-option label="区域二" value="beijing"></el-option>
  </el-select>
</el-form-item>

那由此我们可以设计出封装后样子:

<el-form-item label="label" prop="prop">
  // 如果是input类型 
  <el-input v-if="input" v-model="ruleForm.name"></el-input>
  // 如果是select类型 
  <el-select v-if="select" v-model="ruleForm.region" placeholder="请选择活动区域">
    <el-option label="区域一" value="shanghai"></el-option>
    <el-option label="区域二" value="beijing"></el-option>
  </el-select>
</el-form-item>
  • 表单联动、自定义、事件等等(请看↓↓组件内部)。
  • 组件使用方法:(请查看《form表单API》)
组件内部template:
<template>
  <div class="Form">
    <el-form
      ref="form"
      class="page-form"
      :class="className"
      :model="data"
      :rules="rules"
      :label-width="labelWidth"
    >
      <el-form-item
        v-if="!item.Noshow"
        v-for="(item, index) in fieldList"
        :key="index"
        :prop="item.value"
        :label="item.label+''"
        :class="item.className"
        :style="typePattern? 'float: left;':''"
      >
        <!-- 普通输入框 -->
        <el-input
          v-if="item.type === 'input' || item.type === 'password'"
          v-model="data[item.value]"
          :type="item.type"
          :placeholder="getPlaceholder(item)"
          @blur="blurEvent(item.event)"
          :show-password="item.showPassword"
          :style="item.style"
        />
        <!-- 文本输入框 -->
        <el-input
          v-if="item.type === 'textarea'"
          v-model.trim="data[item.value]"
          :type="item.type"
          :disabled="item.disabled"
          :placeholder="getPlaceholder(item)"
          :autosize="{minRows: 2, maxRows: 10}"
          :maxlength="item.maxlength"
          show-word-limit
          @blur="blurEvent(item.event)"
        />
        <!-- 计数器 -->
        <el-input-number
          v-if="item.type === 'inputNumber'"
          v-model="data[item.value]"
          :step="item.step"
          size="small"
          :min="item.min"
          :max="item.max"
        />
        <!-- 选择框 -->
        <el-select
          v-if="item.type === 'select'"
          v-model="data[item.value]"
          :disabled="item.disabled"
          :clearable="item.clearable"
          :filterable="item.filterable"
          :placeholder="getPlaceholder(item)"
          @change="changeEvent(item.event, data[item.value])"
        >
          <el-option
            v-for="(childItem, childIndex) in listTypeInfo[item.list]"
            :key="childIndex"
            :label="childItem.label"
            :value="childItem.value"
          />
        </el-select>
        <!-- 联选择器 -->
        <el-cascader
          v-if="item.type === 'cascader'"
          v-model="data[item.value]"
          :options="listTypeInfo[item.list]"
          :props="{ expandTrigger: 'hover' }"
          :filterable="item.filterable"
          :clearable="item.clearable"
          @change="changeEvent(item.event, data[item.value])"
        >
        </el-cascader>
        <!-- Radio 单选框 -->
        <el-radio
          v-if="item.type === 'radio'"
          v-for="(childItem, childIndex) in listTypeInfo[item.list]"
          :key="childIndex"
          v-model="data[item.value]"
          :label="childItem.value"
          @change="changeEvent(item.event, data[item.value])"
        >
          {{childItem.label}}
        </el-radio>
        <!-- Checkbox  多选框-->
        <el-checkbox
          v-if="item.type === 'checked'"
          v-for="(childItem, childIndex) in listTypeInfo[item.list]"
          :key="childIndex"
          v-model="data[item.value]"
          :label="childItem.value"
          @change="changeEvent(item.event, data[item.value])"
        >
          {{childItem.label}}
        </el-checkbox>
        <!-- Switch 开关-->
        <el-switch
          v-if="item.type === 'switch'"
          v-model="data[item.value]"
          :active-color="item.color"
        >
        </el-switch>
        <!-- 日期选择框 -->
        <el-date-picker
          v-if="item.type === 'date'"
          v-model="data[item.value]"
          :type="item.dateType"
          :clearable="item.clearable"
          :disabled="item.disabled"
          :placeholder="getPlaceholder(item)"
          :format="item.format"
          :value-format="item.valueFormat"
          :range-separator="item.rangeSeparator"
          :picker-options="listTypeInfo[item.list]"
          unlink-panels
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        />
        <!-- 时间选择框 -->
        <el-time-picker
          v-if="item.type === 'time'"
          :is-range="item.isRange"
          v-model="data[item.value]"
          :range-separator="item.rangeSeparator"
          :placeholder="getPlaceholder(item)"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
        >
        </el-time-picker>
        <!-- 自定义标签 -->
        <div v-if="item.type === 'tag'">
          <el-tag
            v-for="childItem in data[item.value]"
            :key="childItem"
            closable
            :disable-transitions="false"
            @close="handleClose(childItem,item.value)"
          >
            {{childItem}}
          </el-tag>
          <el-input
            class="input-new-tag"
            v-if="inputVisible"
            v-model="inputValue"
            ref="saveTagInput"
            @keyup.enter.native="handleInputConfirm(item.value)"
            @blur="handleInputConfirm(item.value)"
          >
          </el-input>
          <el-button v-else class="button-new-tag" size="small" @click="showInput">{{item.btnName}}</el-button>
        </div>
        <!-- solt 通过具名插槽来实现多个自定义-->
        <template v-if="item.type === 'slot'">
          <slot :name="'form-' + item.value" />
        </template>
      </el-form-item>
      <div v-if="isShowBtn" class="btn" :style="typePattern? 'float: left;margin-left: 20px;':''">
        <el-button type="primary" @click="submitForm('form')">{{typePattern?'查 询':'提 交'}}</el-button>
        <el-button v-if="typePattern" @click="resetForm('form')">重 置</el-button>
      </div>
    </el-form>
  </div>
</template>
定义参数及事件:
<script>
  export default {
    name: 'wb-form',
    props: {
      // 自定义类名
      className: {
        type: String
      },
      // 表单数据
      data: {
        type: Object
      },
      // 相关字段
      fieldList: {
        type: Array
      },
      // 验证规则
      rules: {
        type: Object
      },
      // 相关的列表 (必填)
      listTypeInfo: {
        type: Object
      },
      // label宽度
      labelWidth: {
        type: String,
        default: '100px'
      },
      // 展示类型(是否启用浮动模式)
      typePattern: {
        type: Boolean
      },
      // 是否显示按钮(不显示则自定义按钮)
      isShowBtn: {
        type: Boolean,
        default: true
      }
    },
    data () {
      return {
        // 是否显示标签名称
        inputVisible: false,
        //  添加的新标签名
        inputValue: ''
      }
    },
    // watch: {
    //   data: {
    //     handler: function (val) {
    //       console.log(val)
    //       // 将form实例返回到父级
    //       this.$emit('updateRef', this.$refs.form)
    //     },
    //     deep: true // 深度监听
    //   },
    // },
    methods: {
      /**
       * placeholder 输入框占位文本
       * 通过方法,里面处理你想要的数据,最终return 出去
       * */
      getPlaceholder (row) {
        let placeholder;
        if (row.type === 'input' || row.type === 'textarea' || row.type === 'password') {
          placeholder = '请输入' + row.label
        } else if (row.type === 'select' || row.type === 'time' || row.type === 'date') {
          placeholder = '请选择' + row.label
        } else {
          placeholder = row.label
        }
        return placeholder
      },
      /**
       * 绑定的相关事件
       * 可扩展Element 所有Event事件,以下都是常用的事件,(可自行扩展)
       * */
      // 失去焦点事件
      blurEvent (evnet) {
        let data = {
          evnetName: evnet,
        };
        this.$emit('blurEvent', data)
      },
      // 发生改变的时候
      changeEvent (evnet, value) {
        let data = {
          evnetName: evnet,
          value: value
        };
        this.$emit('changeEvent', data)
      },
      // 派发按钮点击事件
      handleClick (event, data) {
        this.$emit('handleClick', event, data)
      },
      /**
       * 标签专用函数
       * */
      // 关闭标签
      handleClose(item,name) {
        this.data[name].splice(this.data[name].indexOf(item), 1);
      },
      // 显示input
      showInput() {
        this.inputVisible = true;
      },
      // 失去焦点,所做的事情
      handleInputConfirm(list) {
        let inputValue = this.inputValue;
        if (inputValue) {
          this.data[list].push(inputValue);
        }
        this.inputVisible = false;
        this.inputValue  = '';
      },
      /**
       * 提交表单
       * */
      submitForm (formName) {
        if(this.type){
          this.$emit('success')
        }else {
          this.$refs[formName].validate((valid) => {
            if (valid) {
              this.$emit('success')
            } else {
              console.log('error submit!!');
              return false;
            }
          });
        }
      },
      // 清除表单
      resetForm (formName) {
        this.$refs[formName].resetFields();
      }
    },
    mounted () {
      // 将form实例返回到父级 (为了更方便使用Ref)
      this.$emit('formRef', this.$refs.form)
    },
  }
</script>
样式处理
<style scoped>
  .el-tag + .el-tag {
    margin-left: 10px;
  }
  .button-new-tag {
    margin-left: 10px;
    height: 32px;
    line-height: 30px;
    padding-top: 0;
    padding-bottom: 0;
  }
  .input-new-tag {
    width: 90px;
    margin-left: 10px;
    vertical-align: bottom;
  }
  .btn{
    display: flex;
    justify-content: center;
    align-items: center;
  }
</style>
添加自定义事件案例:
 <el-input
          v-if="item.type === 'input' || item.type === 'password'"
          v-model="data[item.value]"
          :type="item.type"
          :placeholder="getPlaceholder(item)"
          @blur="blurEvent(item.event)"   <!--这个是重点 -->
          :show-password="item.showPassword"
          :style="item.style"
        />
  methods: {
   	  /**
       * 可扩展Element 所有Event事件,以下都是常用的事件,(可自行扩展)
       * 思路:给每一个元素添加相同事件,通过event名称来区分事件,然后写你的逻辑代码
       * */
      // 失去焦点事件(这个是重点)
      blurEvent (evnet) {
        let data = {
          evnetName: evnet,
        };
        this.$emit('blurEvent', data)
      },
  }
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Vue ElementUI提供了丰富的表单组件,但是在实际开发中,我们可能需要对表单进行封装,以便于复用和统一管理。以下是一些封装表单的思路: 1. 将表单组件封装成一个单独的组件,包括表单项、校验规则、提交事件等。这样可以将表单的逻辑和UI分离,方便维护和修改。 2. 使用插槽(slot)来动态渲染表单项,可以根据需要添加、删除、修改表单项,提高表单的灵活性。 3. 将表单项的校验规则封装成一个单独的对象,可以在多个表单中复用,减少代码冗余。 4. 使用v-model来双向绑定表单数据,方便获取和提交表单数据。 5. 使用ElementUI提供的表单验证规则,可以快速实现表单的校验功能,减少开发时间和代码量。 总之,封装表单可以提高代码的复用性和可维护性,同时也可以提高开发效率和代码质量。 ### 回答2: Vue是一个流行的前端框架,Element UI则是一个基于Vue框架的UI库。在Vue应用程序中使用Element UI封装form表单,可以简化表单的开发流程,并且可以提供一致性的UI风格。 Element UI提供了大量的表单组件,如输入框、下拉框、日期选择等。在Vue中使用Element UI表单组件,需要对其进行封装,以便可以更方便地使用。 首先,在Vue组件中引入ElementUI库,可以通过install方法进行注册。在组件中注册可以方便使用,同时也可以控制内部封装实现,让表单组件更加灵活地适应业务场景。 其次,需要定义表单数据模型,可以使用组件中的data对象来定义,每个数据字段对应一个表单输入框。将表单数据模型和Element UI组件双向绑定,可以实现对表单数据的自动更新。 然后,定义表单校验规则,可以使用Element UI提供的Validator组件,同时也可以自定义校验规则。在提交表单前进行表单校验,可以避免用户输入不合法数据造成数据异常。 最后,封装表单提交方法,可以使用Vue的methods方法进行实现。在提交表单时,需要将表单数据转换为JSON格式,以便可以进行后续处理。 综上所述,通过对Element UI表单组件进行封装,可以实现更加便捷、高效、可维护的表单开发。同时,也可以提高用户体验,降低用户输入错误的概率,提高数据的准确性和可靠性。 ### 回答3: Vue ElementUI是一套基于Vue.js的UI组件库,它的封装了丰富的组件和样式,使得我们在编写前端页面时可以快速搭建页面、提高开发效率。其中Form表单组件是最常用的之一。 在Vue Element UI中使用Form表单组件时,我们往往会发现它所提供的属性和方法已经足够满足我们大部分的需求。但是,在实际开发中,我们可能会遇到一些特殊的需求,需要封装一些自定义的逻辑和验证规则,比如异步校验、业务逻辑校验。这时候,我们就需要对Vue ELementUI的Form表单组件进行封装封装Form表单组件的目的就是为了封装我们常用的数据校验、提交等逻辑,提高代码的重用性和可维护性。在封装时,我们需要考虑以下几个方面: 1.表单数据的绑定: 在封装时,我们需要考虑表单数据的双向绑定,通常我们会将表单数据绑定在组件的数据对象中,并且在数据对象中提供一个reset方法,用于重置表单数据。 2.验证规则的扩展: 在Vue Element UI中,每个表单控件都可以设置相应的验证规则,比如必填、邮箱、手机号等等,但是有时候我们会遇到一些特殊的需求,比如异步校验、业务逻辑校验等,我们需要对这些验证进行特殊处理,可以通过自定义的验证方法来实现。 3.表单提交: 封装表单的最终目的就是为了实现表单的提交,并处理提交的结果。我们可以将表单的提交和结果处理封装成方法,并以事件的形式发布出去,供父组件调用。 综上所述,封装Vue ElementUI的Form表单组件可以帮助我们提高代码的重用性和可维护性,减少代码的重复编写。同时,也可以使得我们的前端页面开发更加高效,更好地实现页面交互效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值