使用Ts实现class-validator的isNotEmpty注解

安装 reflect-metadata

npm i reflect-metadata

 tsconfig.json中配置

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "experimentalDecorators": true,//支持装饰器写法
    "emitDecoratorMetadata": true,//支持Reflect的Metadata扩展
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

 使用装饰器

import 'reflect-metadata'
class Err {
  msg
  constructor(msg = '不能为空') {
    this.msg = msg
  }
}
// 自定义属性装饰器 IsNotEmpty
function IsNotEmpty(target: any, propertyName: string) {
  Reflect.defineMetadata('IsNotEmpty', true, target, propertyName)
}
// 校验函数
function validateNotEmpty(
  target: any,
  _propertyName: string,
  descriptor: PropertyDescriptor
) {
  //缓存方法原来的值
  const method = descriptor.value
  //对方法更改并执行
  descriptor.value = function (...args: any[]) {
    for (const key in this) {
      const needVal = Reflect.getMetadata('IsNotEmpty', target, key)
      if (needVal) {
        const val = this[key as keyof PropertyDescriptor]
        if (!val || (typeof val === 'string' && !val.trim())) {
          throw new Err(`${key}不能为空`)
        }
      }
    }
    //在最后执行原来的方法
    return method.apply(this, args)
  }
}


// 使用装饰器
class Example {
  @IsNotEmpty
  public name: string

  constructor(name: string) {
    this.name = name
  }

  @validateNotEmpty
  public greet() {
    console.log(`Hello, ${this.name}!`)
  }
}

// 测试,此时name为空,会捕获到错误
const example = new Example('   ')
try {
  example.greet()
} catch (err) {
  console.log(err)
}

在vue中使用装饰器创造响应式对象 

import { reactive } from 'vue'
import 'reflect-metadata'

class Err {
  msg
  constructor(msg = '不能为空') {
    this.msg = msg
  }
}


// 自定义类装饰器 Reactive
function Reactive<T extends { new (...args: any[]): {} }>(my_constructor: T) {
  return class extends my_constructor {
    constructor(...args: any[]) {
      super(...args)
      //把类的实例变成响应式的
      return reactive(this) //返回的是对象,该对象会覆盖constructor返回的对象实例
    }
  }
}


function IsNotEmpty(target: any, propertyName: string) {
  Reflect.defineMetadata('IsNotEmpty', true, target, propertyName)
}

function validateNotEmpty(
  target: any,
  _propertyName: string,
  descriptor: PropertyDescriptor
) {
  const method = descriptor.value
  descriptor.value = function (...args: any[]) {
    for (const key in this) {
      const needVal = Reflect.getMetadata('IsNotEmpty', target, key)
      if (needVal) {
        const val = this[key as keyof PropertyDescriptor]
        if (!val || (typeof val === 'string' && !val.trim())) {
          throw new Err(`${key}不能为空`)
        }
      }
    }
    return method.apply(this, args)
  }
}

// 使用装饰器
@Reactive
class Example {
  @IsNotEmpty
  name: string

  constructor(name: string) {
    this.name = name
  }

  @validateNotEmpty
  greet() {
    console.log(`Hello, ${this.name}!`)
  }
}

   此时,类Example的实例对象就变成了响应式的。修改其实例对象的属性值时,在页面上也会发生变化

给响应式对象赋值

使用自带的校验规则

import { showToast } from 'vant'
import { Validator, validate } from 'class-validator'

/**
 * 自定义表单异常
 * @constructor (message)自定义异常
 */
export class FormException extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'FormException'
  }
}
/**
 * 初始化监听异常的方法
 */
export const ExceptionInterceptor = () => {
  window.addEventListener('error', function (event) {
    if (event.error instanceof FormException) {
      showToast(event.error.message)
    }
  })
  window.addEventListener('unhandledrejection', (event) => {
    const { reason } = event
    if (reason instanceof FormException) {
      showToast(reason.message)
    }
  })
}

//将它的子类用@Reactive变成响应式的类,就可以使用这些方法给响应式对象赋值了
export class FormValidator extends Validator {
  [key: string]: any

  //初始化
  init<T extends Record<string, any>>(form: T) {
    for (const key in form) {
      if (Object.prototype.hasOwnProperty.call(this, key)) {
        this[key] = form[key] as any
      }
    }
  }

  //重置各个属性的值
  reset() {
    const instance = Reflect.construct(this.constructor, [])
    const keys = Object.keys(instance)
    keys.forEach((key) => {
      this[key] = instance[key]
    })
  }

  //表单提交
  submit(): Promise<this> {
    // eslint-disable-next-line no-async-promise-executor
    return new Promise(async (resolve) => {
      const err = await validate(this)
      if (err.length > 0) {
        //需要配合class-validator中的验证注解使用,str为验证失败的提示信息
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const str = Object.values(err[0].constraints!)[0]
        throw new FormException(str)
      }
      resolve(this)
    })
  }
}

自定义校验

import {
  IsNotEmpty,
  Validate,
  ValidatorConstraint,
  ValidatorConstraintInterface
} from 'class-validator'
import { Reactive } from '@/utils/decorator.ts'
import { FormValidator } from '@/utils/FormException.ts'

@ValidatorConstraint()
export class ArrayEachNotEmpty implements ValidatorConstraintInterface {
  validate(value: string[]) {
    if (!Array.isArray(value)) return false
    return value[0] != ''
  }
  defaultMessage() {
    return '错误'
  }
}

@Reactive()
export class UploadCaseDto extends FormValidator {

  @IsNotEmpty({ message: '请输入' })
  not_empty= ''

  @Validate(ArrayEachNotEmpty)
  my_array = ['', '', '']

}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值