封装组件库-弹出框表单

2023, Mar 07    

实现弹出框表单的封装

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

初始配置

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

实现弹出框的基本框架

  • 子组件基本结构
  <div :class="{'choose-icon-dialog-body-height':isScroll}">
    <el-dialog
    v-model='dialogVisible'
    v-bind="$attrs ">
      <template #default>
      </template>
    </el-dialog> 
  </div> 
  
  let emits = defineEmits(['update:visible'])
  
  let props = defineProps({
      visible:{
        type: Boolean,
        default: false
      }
  }
  
  let dialogVisible = ref<boolean>(props.visible)
  
  watch(()=>props.visible,val=>{
    dialogVisible.value = props.visible
  })

  watch(()=>dialogVisible.value,val=>{
    emits('update:visible',val)
  })
  • 父组件基本结构
  <el-button type="primary" @click="open" >open</el-button>
  <my-modal-form v-model:visible="visible"
  :options="options"
  title="编辑用户" 
  width="50%"
  isScroll >
    <template #footer="{form}">
        <el-button @click="cancel(form)">取消</el-button>
        <el-button type="primary" @click="confirm(form)">确认</el-button>
    </template>
    //显示上传组件
    <template #uploadArea>
      <el-button type="primary" size="small">Click to upload</el-button>
    </template>
    <template #uploadTip>
      <div style="color: #ccc;font-size:12px; margin-left:10px">
        jpg/png files with a size less than 500KB.
      </div>
    </template>
  </my-modal-form>
  
  let visible = ref<boolean>(false)
  
  let open = ()=>{
    visible.value = true
  }
  • 父组件表单配置项
  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
  }
},
{
  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
  }
},
{
  type: 'select',
  value: '',
  label: '职位',
  placeholder: '请选择职位',
  prop: 'role',
  attrs: {
    style: {width:'100%'}
  },
  rule:[
    {
      required: true,
      message: '职位不能为空',
      trigger: 'change'
    }
  ],
  children: [
    {
      type: 'option',
      label: '经理',
      value: '1',
      prop: 'jingli'
    },
    {
      type: 'option',
      label: '主管',
      value: '2',
      prop: 'zhuguan'
    },
    {
      type: 'option',
      label: '员工',
      value: '3',
      prop: 'yuangong'
    }
  ]
},
{
  type: 'checkbox-group',
  value: [],
  prop: 'aihao',
  label: '爱好',
  rule: [
    {
      required: true,
      message: '爱好不能为空',
      trigger: 'change'
    }
  ],
  children:[
    {
      type: 'checkbox',
      value: '1',
      prop: 'zuqiu',
      label: '足球'
    },
    {
      type: 'checkbox',
      value: '2',
      prop: 'paiqiu',
      label: '排球'
    },
    {
      type: 'checkbox',
      value: '3',
      prop: 'pingpangqiu',
      label: '乒乓球'
    }
  ]
},
{
  type: 'radio-group',
  value: '',
  prop: 'gender',
  label: '性别',
  rule: [
    {
      required: true,
      message: '性别不能为空',
      trigger: 'blur'
    }
  ],
  children:[
    {
      type: 'radio',
      value: 'male',
      prop: 'male',
      label: '男'
    },
    {
      type: 'radio',
      value: 'female',
      prop: 'female',
      label: '女'
    },
    {
      type: 'radio',
      value: 'not',
      prop: 'baomi',
      label: '保密'
    }
  ]
},
{
  type: 'upload', 
  prop: 'pic',
  label: '上传',
  uploadAttrs:{
    action: 'https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15',
    multiple: true,
    limit: 3
  },
  rule: [
    {
      required: true,
      message: '图片不能为空',
      trigger: 'blur'
    }
  ],
},
{
  type: 'editor',
  value: '',
  prop: 'desc',
  label: '描述',
  placeholder: '请输入描述',
  rule:[
    {
      required: true,
      message: '描述不能为空',
      trigger: 'blur'
    }
  ]
}
]
  • 表单验证方法: form子组件通过方法定义将表单验证和表单数据分发给父组件。
  //表单验证
  let validate = ()=>{
    return form.value!.validate
  }

  //获取表单数据
  let getFormData = ()=>{
    return model.value
  }

  //分发方法,不能直接分发model,只能拿到初始值
  defineExpose({
    resetFields,
    validate,
    getFormData
  })
  <!-- 基于拿到的方法进行表单验证   -->
  <template #footer>
        <slot name="footer" :form="form"></slot>
  </template>
  
  let confirm = (form: any)=>{
    //表单验证的方法,返回值才是方法
    let validate = form.validate()
    let model = form.getFormData()
    validate((valid: any)=>{
      if(valid){
          ElMessage.success('验证成功')
          console.log(model);
          
      }else{
        ElMessage.error('验证失败')
      }
    }) 
}
  • 重置
  let cancel = (form: any)=>{
    visible.value = false
    form.resetFields()
  }