请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

老师,关于min和max的校验,希望能斧正下

export type ValidationKey = 'email' | 'phone' | 'required' | 'range'
interface RuleProp {
  type: ValidationKey;
  message?: string;
  min?: { message: string, length:number};
  max?: { message: string, length:number};
}
interface ResObj {
  isValid: boolean;
  message: string
}
type Validation = Record<ValidationKey, (param: string, rule: Array<RuleProp>) => ResObj>
// Record是ts中高级类型,可以理解为,定义了一系列的对象,对象的属性值为validtaionKey的值,而属性值则是第二个参数决定的,它可以是对象,联合类型,枚举,函数等等,在这个案例中,他是一个函数,
// 函数有一个参数值是字符串类型,该函数会返回一个布尔值
// 邮箱的正则
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
const phoneReg = /^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[0-35-9]\d{2}|4(?:0\d|1[0-2]|9\d))|9[0-35-9]\d{2}|6[2567]\d{2}|4(?:(?:10|4[01])\d{3}|[68]\d{4}|[579]\d{2}))\d{6}$/
// 这个地方他导出的就是一个对象,属性为可以,属性值为方法体
export const Validations:Validation = {
  email (str, rule) {
    const result = { isValid: true, message: '' }
    for (let i = 0; i < rule.length; i++) {
      if (rule[i].type === 'email') {
        result.isValid = emailReg.test(str)
        result.message = rule[i].message as string
        break
      }
    }
    return result
  },
  phone (str, rule) {
    const result = { isValid: true, message: '' }
    for (let i = 0; i < rule.length; i++) {
      if (rule[i].type === 'required') {
        result.isValid = phoneReg.test(str)
        result.message = rule[i].message as string
        break
      }
    }
    return result
  },
  required (str, rule) {
    const result = { isValid: true, message: '' }
    for (let i = 0; i < rule.length; i++) {
      if (rule[i].type === 'required') {
        result.isValid = !!str.trim()
        result.message = rule[i].message as string
        break
      }
    }
    return result
  },
  range (str: string, rule) {
    const newstr = str.trim()
    const result = { isValid: true, message: '' }
    for (let i = 0; i < rule.length; i++) {
      if (rule[i].type === 'range') {
        if (rule[i]?.min) {
          const nummin = rule[i]?.min?.length as number
          if (newstr.length < nummin) {
            result.isValid = false
            result.message = rule[i]?.min?.message as string
            break
          }
        }
        if (rule[i]?.max) {
          const nummax = rule[i]?.max?.length as number
          if (newstr.length > nummax) {
            result.isValid = false
            result.message = rule[i]?.max?.message as string
            break
          }
        }
      }
    }
    return result
  }
}

老师,上面是我将校验规则单独抽离的ts文件,增加了range校验规则

在ValidateInput.vue中,如下定义

<template>
  <div class="validata-input-container pb-3">
    <input
      v-bind="$attrs"
      :class="{'is-invalid': inputRef.error}"
      class="form-control"
      id="exampleInputEmail1"
      :value="inputRef.val"
      @input="updateValue"
      @blur="validateInput">
      <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span>
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, PropType, onMounted, renderSlot } from 'vue'
import { ValidationKey, Validations } from '../hooks/validation'
import { emitter } from './validateForm.vue'
interface RuleProp {
  // ValidationKey是一种类型,可以导入导出使用,那么这里的type就限定了3中,只能是邮箱,手机和必填
  type: ValidationKey;
  message?: string;
  min?: { message: string, length:number};
  max?: { message: string, length:number};
}
// export type RulesProp = RuleProp[],这句话的意思是type是类型别名,这句话的意思就是,创建一个类型,这个类型是个数组类型,每个数组成员是RuleProp类型的数据
// export 只是一个关键字,在ts中,类型可以导出和导入,代码实现也可以导出和到入
export type RulesProp = RuleProp[]
export default defineComponent({
  props: {
    rules: Array as PropType<RulesProp>,
    modelValue: String
  },
  inheritAttrs: false,
  setup (props, context) {
    // 需要判断用户有没有传入默认的初始值,如果传入了需要显示在页面上
    const inputRef = reactive({
      val: props.modelValue || '',
      error: false,
      message: ''
    })
    const updateValue = (e: KeyboardEvent) => {
      // 修改组件的值,实现双向数据绑定
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue
      context.emit('update:modelValue', targetValue)
    }
    const validateInput = () => {
      // 首先判读是否有rules规则
      if (props.rules) {
        // 判断表单所有的是否都通过校验
        for (const rule of props.rules) {
          const resultObj = Validations[rule.type](inputRef.val, props.rules)
          if (!resultObj.isValid) {
            inputRef.error = true
            inputRef.message = resultObj.message
            return false
          }
        }
        inputRef.error = false
      }
    }
    onMounted(() => {
      emitter.emit('form-item-created', inputRef.val)
    })
    return {
      inputRef,
      updateValue,
      validateInput
    }
  }
})
</script>

我传入的规则校验是

    // 密码的校验规则
    const passwordRules: RulesProp = [
      { type: 'required', message: '密码不能为空' },
      { type: 'range', min: { message: '你的密码至少包括六位,不能含有空格', length: 6 }, max: { message: '你的密码至多包括10位,不能含有空格', length: 10 } }
    ]

但是这样会有一个问题,当密码的校验规则既有min也有max的时候,按照我的写法,他永远只会提示,当前密码长度不能小于6个,当超过10个的时候也是提示这个,因为我在动态判断inputRef.message的时候,用的是三元表达式,这样肯定不对的,我需要一个标识,来判断当前到底是min没有通过,还是max没有通过
我的想法是,range方法返回一个对象类似于{ type :‘min’, flag: true},然后在失焦方法触发的时候,去判断这个类型是啥,然后动态设置inputRef.message的信息,但是会遇到问题,希望老师提供一个解决思路

第二个问题,定义rules类型的时候,因为message变成了一个可选参数,inputRef.message = rule.message ? rule.message : ‘’,这里如果直接赋值会报错,rules上不存在message属性,所有这里我使用了三元表达式,不知道这样写合不合乎规范

正在回答 回答被采纳积分+3

2回答

张轩 2022-03-29 10:19:23

同学你好

我发现你遇到的大多数都是 ts 问题,而且你学习的很认真,给你点个赞。这里面你遇到的大多数都是类型问题。我这里简单作答一下。

第一:这个文件不应该放到 hooks 当中,它不是一个 hook

关于 ts,这里有个重要的概念是 type guard,类型保护,它会自动缩小范围,你很多问题都是这样出现的。可以使用if 判断将联合类型中的一部分类型排除出去。https://www.typescripttutorial.net/typescript-tutorial/typescript-type-guards/ 

给你完整的改了一遍,测试完毕,你自己酌情看看,解释了你的疑问,可以好好看下。提交在:

https://gitee.com/wang_shuangqin/those-who-know-also/commit/60fc6b1fd57661db6482ff4dc8a665597b50d7cf



0 回复 有任何疑惑可以回复我~
张轩 2022-03-26 10:07:36

同学你好

写的非常认真,很好,给你点个赞,关于你的问题:我认为可以简单这样修改一下,没有测试,只是提供一个思路

  range (str: string, min?:minMax, max?: minMax) {
    // 初始化一个最终结果
    const result = { isValid: true, message: '' }
    const newstr = str.trim()
    if (min) {
      // 只可能通过一条条件,或大或小
      if (newstr.length < min.length) {
        result.isValid = false
        result.message = min.message
      }
    }
    if (max) {
      if (newstr.length > max.length) {
        result.isValid = false
        result.message = max.message        
      }
    }
    // 返回这个结果,用 isValid 判断是否通过,用 message 显示错误信息
    return result
  }



0 回复 有任何疑惑可以回复我~
  • 老师,我这样修改了一下,还请帮忙看看,遇到很多了很多问题:
    1:比如我现在把min和max换成了可选参数,那么在使用得时候会报错,因为他有可能是undefined,所以这个时候我用类型断言,比如再required得校验函数中我是这么使用得result.message = rule[i].message as string,感觉好像类型断言得用处就在这里,当一个变量有多种形式,而你知道他一定会是这个类型而非undefined得时候,就可以使用(果然用用才能体会到)
    2.整个校验方法我都做了改变,现在我所有得校验方法都不返回布尔值,而是一个对象const result = { isValid: true, message: '' },但是有个问题是,比如一个邮箱,我传入得校验规则有两个,分别是格式和必填,那么我就不能避免得会使用到循环,见代码,那么如果我定义n种检验类型,那么可能这些方法里我都会用到循环,感觉有点蠢,有什么其他得好方法么?
    3:   我如果直接这样写 newstr.length < rule[i]?.min?.length 他会报错,是RuleProp | undefined,所以我这里又用到类型断言,但是这样写会报错newstr.length < rule[i]?.min?.length as number, 大致意思是boolean和number不能比较,我想说如果以后遇到这种比较,是否都要定义一个变量先接收下类型断言之后得值,再开始比较
      if (rule[i]?.min) {
              const nummin = rule[i]?.min?.length as number
              if (newstr.length < nummin) {
                result.isValid = false
                result.message = rule[i]?.min?.message as string
                break
              }
            }
    老师,提问区代码我重新改了下,麻烦您指导下哈
    回复 有任何疑惑可以回复我~ 2022-03-26 22:45:38
  • 同学 你可以把代码库(git)给我,我帮你本地试试,直接用代码还是比较直观的。
    回复 有任何疑惑可以回复我~ 2022-03-27 09:26:00
  • https://gitee.com/wang_shuangqin/those-who-know-also/invite_link?invite=3fa1dd81fbc2a1346989a4339f36cbbf0b3bbb1a57c4802ab7993663152babc55e6dd44c087a1f425f318cd36bbddc3a,老师,您加入就能看哈,谢谢老师
    回复 有任何疑惑可以回复我~ 2022-03-28 10:43:38
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信