封装组件库-表单(4)

2023, Mar 07    

实现表单的封装

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

实现的功能

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

初始配置

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

实现富文本编辑器的集成

  • 为了扩展表单的功能,将WangEditor编辑器集成到表单组件中
  • 类型定义
  export interface FormOptions {
    type: 'editor'
  } 
  • 父组件配置表单数据
  let options: FormOptions[] =[
    {
      type: 'editor',
      value: '',
      prop: 'desc',
      label: '描述',
      placeholder: '请输入描述',
      rule:[
        {
          required: true,
          message: '描述不能为空',
          trigger: 'blur'
        }
      ]
    }
  ]
  • 子组件:单独处理富文本编辑器组件。
  <el-form-item :prop="item.prop" :label="item.label" 
    v-if="!item.children || !item.children.length">
    <component 
    v-if="item.type !== 'upload' && item.type !== 'editor'"
    v-bind="item.attrs" 
    :is="`el-${item.type}`"
    v-model="model[item.prop]"
    :placeholder="item.placeholder">
    </component>
    <el-upload >
    </el-upload>
    <!-- 富文本编辑器 -->
    <div v-if="item.type === 'editor'" id="editor" style="width:100%"></div>
  </el-form-item>
  
  <!-- 在初始化表单时,对富文本编辑器进行初始化 -->
  let initForm = ()=>{
  if(props.options && props.options.length) {
    let m: any = {}
    let r: any = {}
    props.options.map((item: FormOptions)=>{
      m[item.prop] = item.value
      r[item.prop!] = item.rule as any
      //初始化富文本
      if(item.type === 'editor'){
        //操作dom元素,用nextTick,获取editor,设置placeholder,创建富文本编辑器
        nextTick(()=>{
          if(document.getElementById('editor')){
            const editor = new E('#editor')
            editor.config.placeholder = item.placeholder!
            editor.create()
            //初始化富文本的内容,改变输入框内容,desc描述不变,并没有改变表单值,调用onchange
            editor.txt.html(item.value)
            editor.config.onchange = function (newHtml: string) {
              model.value[item.prop!] = newHtml
            };
            edit.value = editor
          }
        })
      }
    })
    model.value = cloneDeep(m)
    rules.value = cloneDeep(r)
  }
}

表单组件的提交与重置的实现

  • 子组件:在el-form组件里设置一个action插槽,给el-form设置ref,同时从插槽里将表单和数据给父组件。form表单实例的类型官网没有提供,在源码里找到接口类型。
  <el-form ref='form' :model="model">
    <el-form-item>
        <slot name="action" :form="form" :model="model"></slot>
    </el-form-item>
  </el-form>
  • 父组件
  <!--   作用域插槽,含提交和重置按钮 -->
  <template #action="scoped">
    <el-button type="primary" @click="submitForm(scoped)">提交</el-button>
    <el-button @click="resetForm">重置</el-button>
  </template>
  <!-- 作用域插槽接收实例的接口类型   -->
  interface Scoped{
    form: FormInstance,
    model: any
  }
  <!-- 提交   -->
  let submitForm = (scoped: Scoped)=>{
      //表单验证是否通过,ELMessage组件提示
      scoped.form.validate(valid=>{
        if(valid){
          console.log(scoped.model);
          ElMessage.success('提交成功!')

        }else{
          ElMessage.error('表单填写有误,请重试!')
        }
      })
  }
  <!-- 重置表单,因为集成了富文本,所以要重写重置方法   -->
  let resetForm = ()=>{
      form.value.resetFields()
  }
  • 子组件重写resetFields方法,vue3的ref无法将方法传递出去,使用提出的defineExpose将方法分发出去
  //重写重置表单的方法
  let resetFields = ()=>{
    //重置element-plus表单
    form.value!.resetFields()
    //重置富文本编辑器的内容
    //获取到富文本的配置项
    if(props.options && props.options.length){
      let editorItem = props.options.find(item=>item.type==='editor')!
      //赋值为富文本的初始值
      edit.value.txt.html(editorItem.value)
    }
  }
  
  //分发方法
  defineExpose({
    resetFields
  })