Skip to content

每日一题:自定义表单验证器

作者:江月迟迟
发表于:2024-12-10
字数统计:1672 字
预计阅读6分钟

介绍

自定义表单验证器是一种在 Web 开发中常用的技术,用于验证用户输入的数据是否符合特定的规则或要求。通过自定义表单验证器,我们可以对表单字段进行验证,并在用户提交表单之前检查数据的有效性。

准备

本题已经内置了初始代码,打开实验环境,目录结构如下:

txt
├── components
│   ├── FormInput.js
│   └── FormValidator.js
├── css
├── index.html
├── js
│   └── util.js
└── lib
    └── vue.global.js

其中:

  • index.html 是主页面。
  • css 是存放项目样式的文件夹。
  • lib 是存放项目依赖的文件夹。
  • components/FormInput.jsinput 组件。
  • components/FormValidator.js 是表单验证器组件。
  • js/util.js 是项目需要用到的工具函数。

注意:打开环境后发现缺少项目代码,请手动键入下述命令进行下载:

bash
cd /home/project
file="formval" && wget "https://labfile.oss.aliyuncs.com/courses/19791/${file}.zip" && unzip "${file}.zip" && rm "${file}.zip"

选中 index.html 右键启动 Web Server 服务(Open with Live Server),让项目运行起来。接着,打开环境右侧的【Web 服务】,就可以在浏览器中看到如下效果:

初始效果

目标

  1. 完成 FormInput.js 中的 TODO 部分,当输入框(class= form-input) 的值变化时,触发事件更新index.html 中组件(form-input)的 v-model 值。(调试 tips:考生可以在点击按钮时通过打印 formData 的值进行查看)。
  2. 完成 js/util.js 中的 is_email 函数,参数是邮箱地址,是合法邮箱返回 true,否则返回 false

合法邮箱包含两个部分:

  1. 用户名部分:
    • 用户名的结尾是 @ 符。
    • @ 符之前为至少 1 位字符(数字或字母)。
  2. 域名部分:
    • 中间必须是 .
    • . 之前为至少 1 位字符(数字、字母)。
    • . 之后为 2 到 4 位字母。

合法邮箱示例: a@b.cn1A@88.com

不合邮箱示例: 1@1.c1@33.cnAb.cn@

  1. 完成 components/FormValidator.js 中通用表单验证函数 validateForm 中的 TODO 部分。如果表单验证通过,则 Promiseresolve(true),否则为 resolve(false)(此部分代码已提供)。 index.html 中定义的 formRules **对象对应字段的表单值验证失败时,使用 validateForm 函数中提供的 errors 对象,在对应字段中存储错误信息。若某个字段对应的错误信息为多个时,将按照验证规则数组的顺序优先显示,即只显示第一个错误信息。**函数使用的数据通过 props.rules(字段名和对应的验证规则) 和 props.formData(表单数据的键值对) 进行获取。

例: email为空显示了错误信息 邮箱不能为空,则不再显示 邮箱不符合规则或者长度不符 这个错误信息。

errors 数据结构示例:

js
{
    phone: "请输入密码", // 对应字段为 phone 的错误信息
    email: "邮箱不能为空" // 对应字段为 email 的错误信息
}

表单每个字段对应的验证规则为一个数组,验证规则示例的配置如下:

js
// 定义表单验证规则
const formRules = {
  phone: [{ validator: validatePass }], // 针对 phone 字段的验证规则
  email: [
    { required: true, message: "邮箱不能为空" }, // 邮箱字段必填规则
    { type: "email", min: 8, max: 20, message: "类型必须为邮箱" }, // 邮箱格式规则
  ],
};

formRules 对应字段说明如下:

注意:自定义验证函数 validator 不会和其他字段同时出现,其他字段均可同时出现。

参数名(Parameter)类型(Type)描述(Description)
validatorFunction表单自定义验证函数,接受三个参数,分别为 rule 表单验证规则数组,value 验证表单的值,callback 回调函数。如果验证成功,callback 函数不做任何处理;如果验证失败,callback 函数接收参数 error 并将其中的文字存储在 errors 对象中,且参数 error 的值为其调用者传递过来的 new Error('这里是错误信息'),其中错误信息是验证失败的具体描述。callback 函数的调用逻辑 index.html 中已经提供,考生只需实现字段验证及 errors 错误信息存储的逻辑即可。
requiredBoolean表示表单字段是否为必填项。
typeString字段类型,通过 FormValidator 中已提供的 validateByType 函数进行验证,该函数接收的参数为 type,类型正确则返回 true,否则返回 false
minNumber指定表单输入的最小长度。
maxNumber指定表单输入的最大长度。
messageString验证失败时的错误信息

完成后示例效果如下:

完成效果

规定

  • 请严格按照考试步骤操作,切勿修改考试默认提供项目中的文件名称、文件夹路径、class 名、id 名、图片名等,以免造成判题无法通过。

判分标准

  • 完成目标 1,得 5 分。
  • 完成目标 2,得 5 分。
  • 完成目标 3,得 15 分。

总通过次数: 61 | 总提交次数: 162 | 通过率: 37.7%

题解

js
    //  TODO:目标 1 当输入框的值变化时,触发 input 事件更新父组件的 v-model 值
    watch(inputValue, (value) => {
      emit('update:modelValue', value)
    })
    
    //  TODO:end
js
const is_email = (val) => {
  // TODO:目标 2 待补充代码
  return /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(?:\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/.test(val)
}
js
// TODO:目标 3 编写通用的表单验证规则,并将错误信息放置到 errors 对象中
        console.log(props.rules);
        console.log(Object.keys(props.formData));
        for(let key of Object.keys(props.formData)) {
          // console.log(props.formData[key]);
          for(let rule of props.rules[key]) {
            console.log(rule);
            if (key in errors) {
              break
            }
            // console.log('validator' in rule);
            if ('validator' in rule) {
              rule.validator(rule, props.formData[key], (error) => {if(error) errors.value[key] = error.message})
            }
            if ('required' in rule) {
              if (rule.required && props.formData[key] === '') {
                errors.value[key] = rule.message
              }
            }
            if ('type' in rule && rule.type === 'email') {
              if (!validateByType(rule.type, props.formData[key]) || props.formData[key].length < rule.min || props.formData[key].length > rule.max) {
                errors.value[key] = rule.message
              }
            }
          }
        }
        // TODO:END