策略模式解决表单提交校验的多重if else问题

196 阅读2分钟

一、表单校验问题优化

我们在做一些比表单提交的需求时,经常会做一些必填校验或正则校验,比如我们可以按照下面的方式进行,使用if else来实现

<button @click='submitData'>提交</button>
methods:{
    submitData () {
            if(!values.username){  
                this.$message.error("用户名不能为空")  
            } else if(!values.password){  
                this.$message.error("密码不能为空")  
            } else if(!values.phoneNumber){  
                this.$message.error("手机号不能为空")  
            } else {  
                this.submit();  
            }
    }
}


可能有人会说,上面的代码语义明确,写得还不够好吗?但是如果需要增加更多的校验条件时,开发者不得不侵入到具体方法去修改代码,使用策略模式优化之后能够让校验条件与具体判断逻辑解耦,当需要增加校验条件时直接修改数组即可:

下面是使用vue3实现,虽然elementPlus自身也有表单校验功能,此例子只是为了说明如何使用策略模式来解决代码多重if else问题

<template>
  <div class="form-wrap">
    <el-form ref="formRef" :model="formData" label-width="100px">
      <el-form-item label="姓名">
        <el-input v-model="formData.name"></el-input>
      </el-form-item>
      <el-form-item label="年龄">
        <el-input v-model="formData.age"></el-input>
      </el-form-item>
      <el-form-item label="手机号">
        <el-input v-model="formData.phoneNo"></el-input>
      </el-form-item>
      <el-form-item label="地址">
        <el-input v-model="formData.address"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">提交</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { reactive } from 'vue'
const formData = reactive({
  name: '',
  age: '',
  phoneNo: '',
  address: ''
})
const validators = [
  { message: '用户名不能为空', required: true, key: 'name' },
  { message: '年龄不能为空', required: true, key: 'age' },
  { message: '手机号不能为空', required: true, key: 'phoneNo' },
  { message: '地址不能为空', required: true, key: 'address' },
  { message: '年龄必须在18-30之间', required: true, key: 'age', pattern: /^(1[89]|20|30)$/ }
]
function validator(values) {
  const result = validators.some(el => {
    // 必填校验
    if (el.required && !values[el.key]) {
      ElMessage.error(el.message)
      return true
    }
    // 正则校验
    if (el.pattern && !el.pattern.test(values[el.key])) {
      ElMessage.error(el.message)
      return true
    }
  })
  return result
}

const onSubmit = () => {
  const values = {
    name: formData.name,
    age: formData.age,
    phoneNo: formData.phoneNo,
    address: formData.address
  }
  if (validator(values)) {
    return
  } else {
    ElMessage.success('提交成功')
  }
}
</script>

<style scoped lang="less">
.form-wrap {
  background: #fff;
  margin-top: 100px;
  color: #333;
  min-height: 100vh;
}
</style>

二、动态表单优化

在使用elementui开发管理系统时,table表格要根据不同条件动态显示


 <el-table-column
            v-for="(item, index) in columnData"
            :key="index"
            :prop="item.name"
            :label="item.label"
            align="center"
            show-overflow-tooltip
   ></el-table-column>
   
   data () {
       return {
           columnData:[]
       }
   },
   methods:{
       changesInRegional () {
            if (this.showContextValue == 1) {
                var taskColumnData = [
                      { name: 'shippingNoteNumber', label: '运单号' },
                      { name: 'consignmentDateTime', label: '托运时间' },
                      { name: 'businessTypeCode', label: '业务类型代码' },
                      { name: 'statisticsType', label: '统计类型' },
                      { name: 'shipperName', label: '托运人名称' },
                 ]
                 this.columnData = taskColumnData
            } else if (this.showContextValue == 2) {
                 var driverColumnData = [
          // 驾驶员基本信息
                  { name: 'nameOfPerson', label: '承运人名称' },
                  { name: 'gender', label: '性别' },
                  { name: 'identityDocumentNumber', label: '身份证号' },
                  { name: 'mobileTelephoneNumber', label: '手机号' },

                  { name: 'vehicleClass', label: '准驾车型' },
                  { name: 'qualificationCertificateNumber', label: '从业资格信息证号' }
                ]
                this.columnData = driverColumnData
            } else if() {
                .......
            } 
       }
   }

如果showContextValue的值有十几个,按照上面的if else写法,代码看起来会非常难受,可以用下面的map写法,让代码看起来好看,并且容易维护

changesInRegional() {
  const contextMapping = {
    1: [
      { name: 'shippingNoteNumber', label: '运单号' },
      // ... 其他字段
    ],
    2: [
      { name: 'nameOfPerson', label: '承运人名称' },
      // ... 其他字段
    ],
    3: [
      { name: 'vehicleNumber', label: '车牌号' },
      // ... 其他字段
    ],
    // ... 其他映射
  };

  const selectedContext = contextMapping[this.showContextValue];
  
  if (selectedContext) {
    this.columnData = selectedContext;
  }
}

三、根据身份证号前2位识别省份

//  idCard为身份证号码
 getProvinceFromIdCard(idCard) {
      var provinceCode = idCard.substr(0, 2)
      var provinceMap = {
        11: '北京市',
        12: '天津市',
        13: '河北省',
        14: '山西省',
        15: '内蒙古自治区',
        21: '辽宁省',
        22: '吉林省',
        23: '黑龙江省',
        31: '上海市',
        32: '江苏省',
        33: '浙江省',
        34: '安徽省',
        35: '福建省',
        36: '江西省',
        37: '山东省',
        41: '河南省',
        42: '湖北省',
        43: '湖南省',
        44: '广东省',
        45: '广西省',
        46: '海南省',
        50: '重庆市',
        51: '四川省',
        52: '贵州省',
        53: '云南省',
        54: '西藏自治区',
        61: '陕西省',
        62: '甘肃省',
        63: '青海省',
        64: '宁夏回族自治区',
        65: '新疆维吾尔自治区',
        71: '台湾省',
        81: '香港特别行政区',
        82: '澳门特别行政区'
      }

      return provinceMap[provinceCode]
    },