vue3.0组合式API-useForm

4,249 阅读4分钟

更多文章

前言

开始之前先简单介绍一下Form组件,Form组件是通过配置文件生成的表单,可以简单的理解为动态表单,通过数据生成,ok,开始我们今天的主题useForm

介绍

根据目前现有业务针对Form做逻辑层的封装,useForm需要和我们封装的Form配合使用,不满足需求时查漏补缺

基础使用

Form组件是ui层的封装,useForm就是配套的逻辑层,除了非常个性化的业务通过插槽处理外,其余的均是通过数据配置(formConfig)和逻辑层完成ui层的展现效果


<template>
  <Form
    ref="formRef"
    :formData="formData",
    :formConfig="formConfig"
  >
    <el-button @click="searchFormHandle">搜索</el-button>
  </Form>
</template>
<script>
import { ref } from '@vue/composition-api'
import Form from '@/components/form'
import useForm from '@/hooks/useForm'

export default {
  components: { Form },
  setup() {
    // ref
    const formRef = ref()
    // form
    const {
      formData,
      formConfig,
      submitHandle
    } = useForm({
      formRef,
      formData: { member: undefined, time: undefined },
      formConfig: [
        { type: 'input', key: 'member', label: '成员' },
        { type: 'datePicker', key: 'time', label: '时间', kind: 'daterange' },
      ]
    })
    // 搜索
    const searchFormHandle = () => submitHandle(() => console.log('可以开始调用接口了'))

    return {
      formRef,
      formData,
      formConfig,
      searchFormHandle
    }
  }
}

</script>

入参

formConfig配置,假设以inputNumber为例,可以配置min和max: { type: 'inputNumber', min: 0, max: 10 },Form组件的配置目前只有当前场景的配置,查漏补缺

参数说明类型可选值默认值
formRefform-refVueComponent--
formData表单数据,与element-form绑定的model一样Object--
formConfig表单展示配置,需要参考Form组件,与element各表单配置相同Arrary--
formRules表单校验规则,具体参考element校验规则Object--

出参

此处抛出的formData、formConfig、formRules均为响应式数据

参数说明类型可选值默认值
formData表单数据,与element-form绑定的model一样Object--
formConfig表单展示配置,需要参考Form组件,与element各表单配置相同Arrary--
formRules表单校验规则,具体参考element校验规则Object--
submitHandle提交表单Function:Promise(callback)--
resetHandle重置表单&校验(element-form-resetFields方法)Function--
validateField部分校验(element-form-validateField方法)Function(props: array/string)--
clearValidate清除校验(element-form-validateField方法)Function(props: array/string)--
resetFormConfig重置formConfig(重置为初始化传入的配置)Function--
resetFormData重置formData(重置为初始化传入formData)Function--
setConfigs更新整个formConfigFunction(vals: Arrary)--
setConfig更新formConfig某项配置的属性状态Function(key, attr, value)--
getConfig获取formConfig某一项Function(key)--
setFormItem为formData某一项赋值Function(key, value)--
setFormRule设置formRules某一项设置校验规则Function(key, index, value)--
setFormRuleAttr设置formRules某一项某个状态Function(key, index, attr, value)--
loopFormConfig遍历loopFormConfigFunction(callback(item))--
loopFormData遍历loopFormDataFunction(callback(formData, key))--

submitHandle既可以通过callback执行回调,也可以通过Promise形式调用


// callback
submitHandle(() => console.log('我是回调函数,校验通过则会执行'))
// promise
submitHandle().then(valid => valid && console.log('我是接口调用,校验通过则会执行'))

resetFormData主要是解决resetHandle无法达到的数据重置效果,通常在表单类数据回显时会对源数据进行操作,导致resetHandle无法达到想要的效果,resetFormData的作用就是解决这个问题

setConfig: 假设此时不同情况下要设置某个input的disabled状态


// id为1时disabled为true
setConfig('member', 'disabled', id === 1)

setFormRule: 通常配置非常多时会叫配置提到一个配置文件中,而当校验规则需要用到响应式数据formData时,静态的配置文件中无法拿到实时的响应式数据,则需通过setFormRule动态设置校验规则


setFormRule('pass', 1, {
    validator: (rule, value, callback) => {
      const { formData: { pass, rePass } } = formState
      if (creditAmount && orderAmount) {
        if (pass !== rePass) {
          callback(new Error('两次密码不一致'))
          return
        }
      }
      callback()
    },
    trigger: ['blur', 'change']
  }
)

setFormRuleAttr:动态的设置某一项校验或者不校验时


// id为1时必填,否则非必填
setFormRuleAttr('member', 0, 'required', id === 1)

loopFormConfig:编辑时全部展示input框,完成展示text


const kinds = { default: 'text', edit: 'input' }
const kind = 'edit'

loopFormConfig(item => { item.type = kinds[kind])

loopFormData:通常编辑回显时,接口返回的数据非常杂乱,可以通过loopFormData完成数据的回显


loopFormData((formData, key) => {
  if (!data[key]) return
  formData[key] = data[key]
})

源码


import { reactive, toRefs } from '@vue/composition-api'
import { deepCopy } from '@/utils/qjd'

/**
 * 场景:适用于所有表单类提交包括查询,配合components/qjd/form使用,目前组件仅有开发遇到的场景,缺啥补啥,根据实际场景扩展useForm
 * @param formRef form-ref
 * @param formData 初始化数据
 * @param formConfig 表单配置
 * @param formRules 校验规则
 */

export default ({
  formRef,
  formData,
  formConfig,
  formRules
}) => {
  const state = reactive({
    formData: deepCopy(formData),
    formConfig: deepCopy(formConfig),
    formRules: deepCopy(formRules)
  })
  // 提交表单
  const submitHandle = async (callback = null) => {
    try {
      const { value: { submitHandle: forSubmit } } = formRef
      const valid = await forSubmit()
      valid && callback && callback(state.formData)
      return valid
    } catch (error) {
      console.log(`error: ${error}`)
    }
  }
  // 重置表单
  const resetHandle = () => formRef.value && formRef.value.resetHandle()
  // 校验表单部分字段
  const validateField = val => formRef.value && formRef.value.validateField(val)
  // 清除校验
  const clearValidate = val => formRef.value && formRef.value.clearValidate(val)
  // 查询formConfig-item
  const getConfig = key => state.formConfig.find(item => item.key === key)
  // 更新整个formConfig
  const setConfigs = vals => { state.formConfig = deepCopy(vals) }
  /**
   * @param key formConfig - key
   * @param attr formConfig - 属性
   * @param value 设置的值
   */
  const setConfig = (key, attr, value) => {
    if (!key || !attr) return
    const item = getConfig(key)
    if (!item) return
    item[attr] = value
  }
  // formData单个元素赋值
  const setFormItem = (key, value) => {
    if (!key) return
    state.formData[key] = value
  }
  // formRules单个属性配置变更
  const setFormRuleAttr = (key, index, attr, value) => {
    if (!key || !attr) return
    state.formRules[key][index][attr] = value
  }
  // formRules单个配置变更,针对需要动态设置校验规则 | 校验规则依赖于响应式的form数据
  const setFormRule = (key, index, value) => {
    if (!key) return
    state.formRules[key][index] = value
  }
  // 遍历formConfig,通过callbac处理数据
  const loopFormConfig = (callback) => state.formConfig.forEach(item => callback && callback(item))
  // 遍历formData,通过callbac处理数据
  const loopFormData = (callback) => Object.keys(state.formData).forEach(key => callback && callback(state.formData, key))
  // 重置formData
  const resetFormData = () => { state.formData = deepCopy(formData) }
  // 重置formConfig
  const resetFormConfig = () => { state.formConfig = deepCopy(formConfig) }

  return {
    submitHandle,
    resetHandle,
    validateField,
    clearValidate,
    setConfigs,
    setConfig,
    getConfig,
    setFormItem,
    setFormRuleAttr,
    setFormRule,
    loopFormConfig,
    loopFormData,
    resetFormData,
    resetFormConfig,
    ...toRefs(state)
  }
}

结语

form也是比较庞杂的一块,目前暂具功能如上,需要在业务开发中不断的完善