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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值