封装组件库-表单(1)

2023, Mar 07    

实现表单的封装

基于Element-plus框架的Form表单组件进行封装。

实现的功能

  • 实现配置型表单,通过json对象的方式自动生成表单
  • 具备更加完备的功能,表单验证,动态删减表单,集成第三方插件(富文本编辑器)
  • 用法更简单,扩展性强(配置项形式),可维护
  • 能够进行弹框嵌套表单等多场景。

初始配置

  • 注册路由组件form,配置为Container组件的子路由组件
  • 采用路由懒加载,箭头函数异步引入组件。
  • 注册通用组件from,为路由组件的子组件,以便组件间通信。
  • 将通用组件form注册为全局组件

实现基础表单

  • 设计接口类型:Element-plus的表单验证是基于async-validator的验证规则,复制src/interface.ts作为rule.ts,引入接口RuleItem作为表单验证的接口类型。
  import {RuleItem} from './rule'
  export interface FormOptions {
    //表单项显示的元素
    type: 'cascader' | 'checkbox' | 'checkbox-group' | 'check-button' | 'color-picker' | 
    'data-picker' | 'input' | 'input-number' | 'radio' | 'radio-group' | 'radio-button' | 
    'rate' | 'select' | 'option' | 'slider' | 'switch' | 'time-picker' | 'time-select' | 
    'transfer',
    //表单项的值
    value?: any,
    //表单项label
    label?: string,
    //表单项的标识
    prop: string,
    //表单项的验证规则
    rule?: RuleItem[],
    //表单项的占位符
    placeholder?: string,
    //表单项特有的属性
    attrs?: {
        clearable?: boolean,
        showPassword?: boolean,
        disable?: boolean,
    }  
}

用户名输入框组件

  • 父组件配置用户名输入框组件
  <!--   给子组件传递组件的配置项 -->
  <my-form :options="options"></my-form>
  let options: FormOptions[] =[
    {
      type: 'input',
      value: '',
      label: '用户名',
      placeholder: '请输入用户名',
      prop: 'username',
      rule: [
              {
                required: true,
                message: '用户名不能为空',
                trigger: 'blur'
              },
              {
                min: 2,
                max: 6,
                message: '用户名在2-6位之间',
                trigger: 'blur'
              }
            ],
      attrs: {
        clearable: true
      }
    }
  ]
  • 子组件
  <!--   给表单组件绑定表单数据对象model和表单验证规则rules,关闭立即触发验证 -->
  <el-form  v-bind="$attrs" :validate-on-rule-change="false" :model="model" :rules="rules">
        <!-- 遍历表单绑定prop和label -->
        <el-form-item :prop="item.prop" :label="item.label" 
        v-for="(item,index) in options" :key="index">
          <!-- 动态组件指定组件类型,绑定剩余传参,并采用v-model双向绑定 -->
          <component 
          v-bind="item.attrs" 
          :is="`el-${item.type}`"
          v-model="model[item.prop]"
          :placeholder="item.placeholder">
          </component>
        </el-form-item>
  </el-form>
  
  import {FormOptions,FormInstance} from './types/types'
  import cloneDeep from 'lodash/cloneDeep'
  let props = defineProps({
  // 表单的配置项
  options: {
    type: Array as PropType<FormOptions[]>,
    required: true
    }
  })
  
  let model = ref<any>({})
  let rules = ref<any>({})
  
  //初始化表单的方法
  let initForm = ()=>{
    <!-- 判断表单是否为空 -->
    if(props.options && props.options.length) {
      <!-- 用于接收表单数据和规则 -->
      let m: any = {}
      let r: any = {}
      <!-- 遍历表单,获取数据和验证规则,prop为model所需的键名 -->
      props.options.map((item: FormOptions)=>{
        m[item.prop] = item.value
        r[item.prop!] = item.rule as any
      })
      <!-- 进行深拷贝,复制数据备用 -->
      model.value = cloneDeep(m)
      rules.value = cloneDeep(r)
    }
  }
  <!-- 在组件挂载时初始化表单 -->
  onMounted(()=>{
    initForm()
  })

密码输入框组件

  • 父组件配置密码输入框组件
  let options: FormOptions[] =[
    {
      type: 'input',
      value: '',
      label: '密码',
      placeholder: '请输入密码',
      prop: 'password',
      rule: [
        {
          required: true,
          message: '密码不能为空',
          trigger: 'blur'
        },
        {
          min: 6, 
          max: 15,
          message: '密码在6-15位之间',
          trigger: 'blur'
        }
      ],
      attrs: {
        showPassword: true,
        clearable: true
      }
   }
  ]