背景:elementui的el-form已经帮我们封装了常用的表单校验,那他是怎么去校验的呢?看文档发现它是利用了async-validator这个插件去实现的(带着好奇心去学习===知其然更要知其所以然)
另一场景需求实现:当我的项目开发有一些表单项 那我们想要实现校验 是不是一定要依赖于el-form呢?当然不是啦
我们一样可以封装类似el-form的属于自己的组件 通过插件async-validator去实现校验
async-validato的使用:https://zhuanlan.zhihu.com/p/269624748
注意:我们进行校验往往更多是针对多个同时进行的 所以async-validato是异步校验 用到了new Promise(解决异步回调)
el-input校验 封装
<template>
<div class="com-number-input">
<el-input
@blur="onValidate"
@input="onValidate"
v-model="fieldValue"
:placeholder="placeholder"
:clearable="clearable"
>
<template #prepend v-if="'prepend' in slots"><slot name="prepend"></slot></template>
<template #append v-if="'append' in slots"><slot name="append"></slot></template>
</el-input>
<div class="error" v-if="errorMessage">{{ errorMessage }}</div>
</div>
</template>
<script lang="ts" setup name="ComNumberInput">
import { ref, useSlots } from 'vue'
import Schema from 'async-validator'
type Props = {
modelValue?: string | number
rules?: Record<string, any>[]
placeholder?: string
clearable?: boolean
validate?: boolean
}
const props = withDefaults(defineProps<Props>(), {
modelValue: '',
rules() {
return [] as Record<string, any>[]
},
placeholder: '请填写',
clearable: false,
validate: true,
})
const slots = useSlots()
const emits = defineEmits(['update:modelValue', 'update:validate'])
const fieldValue = ref<string | number>('')
const errorMessage = ref<string>('')
const validator = new Schema({
fieldValue: props.rules,
})
const onValidate = () => {
return new Promise((resolve, reject) => {
validator
.validate({ fieldValue: fieldValue.value })
.then(() => {
errorMessage.value = ''
emits('update:modelValue', fieldValue.value)
emits('update:validate', true)
resolve(true)
})
.catch(({ errors, fields }) => {
if (errors.length > 0) {
errorMessage.value = errors[0].message
emits('update:validate', false)
}
reject(errors)
})
})
}
watch(
() => props.modelValue,
(newVal) => {
fieldValue.value = newVal
},
)
onMounted(() => {
fieldValue.value = props.modelValue
})
defineExpose({
validate() {
return new Promise((resolve, reject) => {
onValidate()
.then(() => {
if (errorMessage.value == '') {
resolve(true)
} else {
resolve(false)
}
})
.catch(() => {
resolve(false)
})
})
},
})
</script>
<style lang="scss" scoped>
.com-number-input {
.error {
text-align: left;
color: var(--el-color-danger);
}
}
</style>
调用:
<com-number-input
ref="beginFinalScoreRef"
v-model="paramsForm.beginFinalScore"
class="flex-1"
clearable
:rules="[
{
validator(field, value) {
return !isNaN(value)
},
message: '请输入数字',
},
{
validator(field, value) {
return value >= 0
},
message: '不能为负数',
},
]"
placeholder="数字"
></com-number-input>
const onQuery = async () => {
if (
!((await beginFinalScoreRef.value.validate()) && (await endFinalScoreRef.value.validate()))
) {
return
}
}