Vue3+TS的表单验证逻辑分离

抽离了验证逻辑,可用于登录、表单验证等场景

import {LoadAttributeByPath} from "../LoadAttributeByPath";
import {Ref} from "vue";

type ValidationOptions = {
  base?: string[]
}

class ValidatorUnit<SourceType> {
  targetName: keyof SourceType;
  validateMethod: (val: any, sourceData?: SourceType) => boolean;

  constructor(targetName: any, validateMethod: (val: any, sourceData?: SourceType) => boolean) {
    this.targetName = targetName;
    this.validateMethod = validateMethod;
  }
}

export class Validator<SourceType> {
  sourceData: SourceType = null as unknown as SourceType;
  refSource: Ref<SourceType> = null as unknown as Ref<SourceType>;
  validationList: Array<ValidatorUnit<SourceType>> = [];
  options?: ValidationOptions

  constructor(sourceData: Ref<SourceType>, options?: ValidationOptions) {
    if (options) {
      this.options = options;
    }
    this.refSource = sourceData;
  }

  bind(propName: keyof SourceType, validator: (val: any, sourceData?: SourceType) => boolean) {
    this.validationList.push(new ValidatorUnit(propName, validator));
    return this;
  }

  useTarget(newSource: SourceType) {
    if (this.options?.base) {
      this.sourceData = LoadAttributeByPath(newSource, this.options.base) as SourceType;
    } else {
      this.sourceData = newSource;
    }
  }

  validate(): boolean {
    this.useTarget(this.refSource.value)
    // every: 检测数组是否每个都符合条件
    return this.validationList.every(unit => unit.validateMethod(this.sourceData[unit.targetName], this.sourceData));
  }
}

export function useValidation<SourceType>(sourceData: Ref<SourceType>, options?: ValidationOptions) {
  return new Validator<SourceType>(sourceData, options);
}

但使用的时候要注意,构造函数要传入一个Ref<T>类型

<script setup lang="ts">
import {ref, reactive, PropType, shallowReactive, watch, toRef} from "vue";
import {UserInfo} from "../type/UserInfo";
import {useValidation} from "../utils/use/useValidation";

const props = defineProps({
  userInfo: {
    type: Object as PropType<UserInfo>,
    default: new UserInfo()
  }
})

const UserValidation = useValidation(toRef(props, 'userInfo'))
  .bind('username', (val, instance) => {
    if (val.length < 3) {
      validationResult.value = `name must be at least 3 characters(${JSON.stringify(instance)})`;
      return false;
    }
    return true;
  })
  .bind('password', (val, instance) => {
    if (val < 18) {
      validationResult.value = `password must be greater than 18(${JSON.stringify(instance)})`;
      return false;
    }
    return true;
  });

const validationResult = ref('ve here')

function validate() {
  if (UserValidation.validate()) {
    validationResult.value = 'success';
  }
}
</script>

<template>
  <div class="SubComponent__container">
    {{ props.userInfo }}
    <el-input v-model="props.userInfo.username"/>
    <el-input v-model="props.userInfo.password"/>
    <el-button @click="validate">验证</el-button>
    {{ validationResult }}
  </div>
</template>

<style lang="scss" scoped>
.SubComponent__container {
  height: 70%;
  display: flex;
  align-items: center;
  justify-content: center;

  .el-input {
    width: 200px;
  }
}
</style>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值