新项目开发整理(一)js策略模式应用于表单验证

1,199 阅读3分钟

前言

针对最近开发的新项目做一些技术上的简单整理记录,借此养成随手整理的习惯,本篇主要讲讲策略模式在搭配react hooks在项目中的一些应用

概述

首先为什么要这么做?虽然项目中并没有大量的表单验证,只是简单的验证手机号、密码、邮箱等。但是应用策略模式可以避免前端出现判断增强代码可维护性和可读性,同时搭配useEffect个人认为代码看起来很舒服(当然也有之前面试被问到过如何实现优雅的表单验证所以这次为了用而用的嫌疑😁)

什么是策略模式

相信大家都知道或者看过一些大佬的分享,这里就简单介绍下,策略模式就是一系列独立的算法的封装,在应用于表单验证时我们把各种验证规则封装成独立的方法,上代码:

export const verification = {
  isNotEmpty : value => {
    return value.length !== 0  
  },//判断输入项是否为空
  isSpecifiedLength : (value,len) => {
    return value.length === len
  },//判断输入项的长度是否为指定长度
  isInLengthArea : (value,min,max) => {
    return value.length >= Number(min) && value.length <= Number(max)
  },//判断输入项长度是否符合某区间
  isPhoneFormat : (value) => {
    return /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0-9]|17[0-9])\d{8}$/.test(value)
  },//判断输入项是否为手机号
  isEmail : (value) => {
    return /^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/.test(value)
  }//判断输入项是否为邮箱
}

export class Validator{
  queue
  constructor(){
    this.queue = []//保存校验方法队列
  }
  addRuler(value,rulers){//增加验证规则函数
    let self = this
    for(let i in rulers){
      let rule = rulers[i]
      let args = rule.type.split(':')
      self.queue.push(function(){
        let type = args.shift()
        args.unshift(value)
        return verification[type].apply(self,args)
      })
    }
  }
  check(){//验证函数
    let result_final:boolean = true
    for(let i=0;i<this.queue.length;i++){
      let result = this.queue[i]()
      result_final = result_final && result
    }
    this.queue = []
    return result_final
  }
}

以上代码可以看到,一个策略对象由验证函数队列,增加验证规则方法,验证函数三部分组成,其中要特别说明一下的是,当面临一些不定的规则时,规定了通过":"来做参数的切割,如:

passwordCheck.addRuler(password, [{ type: "isInLengthArea:6:20" }]);
//判断密码是不是在6位到20位之间,这个不定的位数写进规则中,在增加规则时会被切割出,执行时作为参数传入
codeCheck.addRuler(code, [{ type: "isSpecifiedLength:6" }]);
//同理判断是不是长度为6

结合hooks的react组件中应用

/* demo.jsx */
const emailCheck = new Validator();
//初始化对象写在组件外,避免组件更新时频繁新建对象造成不必要的消耗
const Index = () => {
  const [email, setEmail] = useState("")
  const [canSubEmial, setCanSubEmail] = useState(false)
  useEffect(() => {
    emailCheck.addRuler(email, [{ type: "isEmail" }])
    setCanSubEmail(emailCheck.check())
    //email值变化时验证是否为邮箱格式并通过setCanSubEmail设置验证结果
  }, [email])
  return (
    <Fragment>
        <input 
            className="email_input" 
            placeholder="输入邮箱地址" 
            onChange={e => {
                setEmail(e.target.value);
            }}
            value={email}
            type="text"
        />
        <div 
            className={canSubEmial ? "sure_btn can" : "sure_btn"} 
            onClick={() => {
                if(canSubEmail){
                    //逻辑
                }    
            }}
        >确定</div>
        //按钮通过canSubEmial的值绑定不同的状态和是否触发点击逻辑
    </Fragment>
  )
}

以上就是一个简单的验证的demo,假如对useEffect理解不够深的话建议看下这位大佬的分享精读《useEffect 完全指南》

后记

当页面中表单项很多并且存在一定关联时,使用策略模式的优势就会更加明显,举个简单例子,假如某页面存在phone、password、address三个表单项,每个表单项右侧都要根据实时填写内容按验证规则显示符合填写规则icon或不符合填写规则icon,同时下面提交按钮要根据是否三个输入都合规显示正常颜色或者置灰禁用,下面是伪代码:

const [phone, setPhone] = useState(""); //手机号
const [password, setPassword] = useState(""); //密码
const [address, setAddress] = useState(""); //地址
const [phoneRight, setPhoneRight] = useState(false); //手机号是否合规
const [passwordRight, passwordRight] = useState(false); //密码否合规
const [addressRight, addressRight] = useState(false); //地址是否合规
const [canSubmit, SetCanSubmit] = useState(false); //是否可以提交
useEffect(()=>{
    //手机号验证相关
}, [phone])
useEffect(()=>{
    //密码验证相关
}, [password])
useEffect(()=>{
    //地址验证相关
}, [address])
useEffect(()=>{
    //提交按钮相关逻辑
}, [phoneRight, passwordRight, addressRight])