[vue3]表单校验composition api封装(TS实现)

192 阅读1分钟

1 api描述

/**
 * @title useForm
 * @description composition api useForm
 * @params useFormOptions: UseFormOptions<T>
 * @return { form: UnwrapNestedRefs<T> (reactive); valid: (key?: keyof T) => boolean }
 */
  1. 入参:useFormOptions
  2. 返回值:{form, valid}

2 api调用方式

import useForm from '@/use/useForm'

interface LoginForm {
    phone: string
    password: string
    verifyCode: string
}

const { form, valid } = useForm<LoginForm>({
    // 1. 可以设置字段校验规则(以[field]: {$value, $valid?, $invalidCbk?}形式)
    // 2. 也可以不设置校验规则(以[field]: value形式);不设置校验规则的化后续valid校验函数校验该字段会直接返回true
    phone: {
        $value: '',
        $valid: (val) => telRegex.test(val),
        $inValidCbk: () => Toast('手机号格式不正确')
    },
    password: '',
    verifyCode: {
        $value: '',
        $valid: (val) => !!val,
        $inValidCbk: () => Toast('请填写验证码')
    }
})

// -------------- 看看效果 -------------------
console.log(form)   // reactive({phone: '', password:'', verifyCode: ''})

// 1. valid函数支持传入一个或多个表单字段名作为参数,并对这些字段按照前面预设规则进行校验
valid('phone')  // false
form.phone = '13111111111'
valid('phone')  // true
valid('phone', 'password')  // true
// 2. valid函数不传参数默认校验form中的所有字段
valid()   // false; Toast('请填写验证码');

3 api function源码

import { reactive } from 'vue-demi'

type Form = Record<string, any>

interface ValidatorType<T> {
    $value: T
    $valid?: (value: T) => boolean
    $inValidCbk?: (value: T) => void
}

type UseFormOptions<T extends Form> = { [K in keyof T]: ValidatorType<T[K]> | T[K] }


export default function useForm<T extends Form>(useFormOptions: UseFormOptions<T>) {
    const rawForm: any = {};
    Object.entries(useFormOptions).forEach(([key, val]) => {
        rawForm[key as keyof T] = val?.$value ?? val
    })
    const form = reactive<T>(rawForm)
    const valid = (...keys: Array<keyof T>): boolean => {
        const validatorFcn = <K extends keyof T>(key: K, validator: ValidatorType<T[K]>) => {
            const { $valid, $inValidCbk } = validator || {}
            if (!$valid) return true
            const isValid = $valid(form[key])
            if (!isValid) { $inValidCbk?.(form[key]) }
            return isValid
        }
        if (keys) {
            return keys.every(key => {
                const validator = useFormOptions[key]
                return validatorFcn(key, validator)
            })
        } 
        return Object.entries(useFormOptions).every(([key, validator]) => validatorFcn(key, validator))
    }
    return { form, valid }
}

实现难度不大,流程入下:

  1. 对传入的useFormOptions提取出form表单项内容;
  2. valid校验函数通过Array.every()函数对传入的每个字段进行规则校验,所有字段校验通过则返回true,有字段校验不通过则调用该字段前面预设的$inValidCbk函数。