框架的 Form 表单验证,怎么用纯 HTML 实现?

本文截取自《前端开发实战派》

加作者 好友 进全栈开发&源码实战群

大家好,我是杨成功。

HTML5 在原有表单元素的基础上进行了丰富的扩展,主要表现为添加了许多新属性,使之前需要用 JavaScript 才能实现的东西,现在用原生标签很轻松就能实现。

这其中最具有代表性的是 input 元素,它增加了许多新的 type 属性,具体功能如下:

js 复制代码
// 选择日期
<input type="date"/>
// 选择时间
<input type="time"/>
// 选择日期时间
<input type="datetime-local"/>
// 选择月份
<input type="month"/>
// 选择颜色
<input type="color"/>
// 数字输入框
<input type="number" min="1" max="10"/>
// 邮箱输入框
<input type="email"/>
// 滑动条
<input type="range" min="1" max="10"/>

上面这些是最常用的、且都是 Chrome 浏览器支持的 type 值。像选择日期,时间,数字输入框等,在前端表单中经常用到,以前要加一个这样的组件还得引用一些第三方框架,现在直接使用就可以了。

除了带来新功能的 type 属性,input 还增加了非常多有用的其他属性。这些属性扩展了 input 的能力,使表单提交越来越满足我们多样化的需求。新加的常用属性如下:

  • autofocus:自动聚焦
  • autocomplete:自动填充
  • max/min:最大最小值
  • maxlength:最大字符长度
  • disabled:禁用元素
  • readonly:元素只读
  • form:指定所属表单
  • required:必填
  • pattern:自定义验证规则
  • novalidate:提交表单时不验证

这些属性中,autocomplete 设置是否自动填充,在登录页面中我们通常需要设置账户密码自动填充,验证码不需要自动填充。

max/min 属性只有在 type="number" 的时候生效,设置输入数值的最大值和最小值。

maxlength 是对普通字符串输入的限制,规定最多能输入多少个字符。

至于 requiredpatternnovalidate 这些属性,只有当元素作为表单项,也就是 <form> 元素的子项时才会是有用的规则,这些规则的验证会在表单提交时自动触发,验证不通过则阻止表单提交。

pattern 属性很有用,用正则表达式来自定义输入值的规则。比如要输入手机号,那么就可以写一个手机号的正则表达式赋值给 pattern,这样在表单提交时就会验证输入值是不是一个手机号。这个字段使表单项验证的灵活性大大提高。

form 属性的作用是,指定当前元素属于哪个表单。比如一个 input 不在某个 form 标签的包裹之内,默认情况下这个输入框和 form 表单无关,更不会执行该表单的提交和验证规则。但你可以为这个 input 指定 form 属性,值为表单的 id,手动将输入框绑定到这个表单之上。

提示:required,pattern,form 这些属于表单项的属性,不仅仅适用于 input,其他能作为表单项的元素,比如 select,button 也是通用的。

接下来我们就实现一个包含验证功能的基本表单。

验证表单规则

首先定义一个基础的表单结构:

js 复制代码
<form id="form1">
  <input type='text' name="name" placeholder="输入姓名" maxlength="5" required/>
  <input type='number' name="age" placeholder="输入年龄" min="15" max="65" required/>
  <input type='text'name="sex" placeholder="输入性别" required disabled/>
  <input type="submit" value="提交">
</form>

在上述代码中 <form> 元素的平级,增加一个 <input> 元素,并与该表单绑定:

js 复制代码
<input form="form1" name="other" placeholder="输入额外信息" required>

当点击提交的时候,首先第一个 input 的验证被触发了,如图所示:

Form 的验证逻辑是按照子元素的顺序逐个验证,上图中第一个表单项的验证被触发,只有当前表单项验证通过后,才会验证下一个表单项。

需要注意的是,maxlength 规则不需要点提交触发,而是输入的时候自动触发。

第二个表单项:年龄数值输入框。点提交的时候,最大最小值的验证触发了,如图所示:

第三个表单项 :性别输入验证:这块有点特殊,既要求必填,又规定了 disabled

经过试验验证,发现当元素被设为 disabled 时,表单的验证就会失效,将 disabled 换为 readonly 之后,效果也一样。说明在表单项只有可编辑的时候才会有表单验证,否则无效,这也是符合实际情况的。

disabledreadonly 这两个属性非常相似,很多人都不清楚有什么区别,下面我们列一下:

  • disabled 对所有表单类元素有用,readonly 只对文本,密码输入框有用。
  • 设置 disabled 后 JS 获取不到该元素,设置 readonly 则可以。
  • 设置 disabled 后表单数据不会传输,设置 readonly 则依然可以传输。
  • disabled 和 readonly 都会使表单验证失效。

所以当元素被设置为 disabled 或 readonly 之后,相当于同时也设置了 novalidate 属性。

最后一个表单项,它不在 form 包裹之内。当前面验证通过之后,这个元素的验证也被触发了,如图所示:

在一些复杂的页面场景当中,有时候你的输入框可能并不会包裹在 form 元素之内,这个时候你就可以用 form 属性来为输入框绑定表单,和将其放置到 form 标签之内是一样的效果。

表单提交验证

当所有验证通过之后,表单的默认逻辑是将数据提交到某个地址,此时会刷新页面,这不是我们想要的。

在前后端分离的开发模式中,我们更希望的是只获取验证之后的输入值,不刷新页面,拿到值之后自行处理,这该如何实现呢?

其实很简单,第一步,在 form 标签上加一个 onsubmit 事件:

js 复制代码
<form id="form1" onsubmit="onSubmit(this);return false;">
  ...
</form>

这里首先调用一个 onSubmit() 方法,参数 this 代表 form 元素。这里最关键的是在最后面加一个 return false,它可以阻止默认的页面刷新。

onSubmit() 方法只会在表单验证通过之后调用,所以我们不用考虑未验证通过的情况。只需要在这个方法之内获取到每个表单项的 name 和 value,组成一个我们需要的数据对象即可:

js 复制代码
function onSubmit(e) {
  let form_data = {}
  Array.from(e.children)
    .filter(el => el.name)
    .forEach(el => {
      form_data[el.name] = el.value
    })
  console.log(form_data)
}

这个代码中有两个部分需要注意:一是将 e.children 这个类数组转换成数组。第二是要用 fliter 过滤一下没有提供 name 属性的表单项,最后组合而成的就是我们想要的数据。

当然,e.children 仅仅是获取直接子元素的方法,也可以用 querrySelector() 代替。

总结

本文介绍了 HTML5 中新的表单选项,并进行了具体应用和实例验证。对比前端框架中的表单组件,会发现很多功能就是原生 HTML 元素提供的,而非 JavaScript 实现。

本文截取自我的新书《前端开发实战派》 第二章,属于核心基础的部分。更多系列文章,查看我的公众号 程序员成功

相关推荐
heartmoonq2 分钟前
关于前端监控用户行为导致的报错
前端
已读不回1433 分钟前
告别痛苦的主题切换!用一个插件解决 Tailwind CSS 多主题开发的所有烦恼
前端·架构
pepedd8643 分钟前
🚀Webpack 从入门到优化,一文全掌握!
前端·webpack·trae
TimelessHaze4 分钟前
【面试考点】从URL输入到页面展示
前端·trae
玲小珑6 分钟前
LangChain.js 完全开发手册(一)AI 应用开发入门
前端·langchain·ai编程
excel6 分钟前
前端必修:从表单基础到富文本编辑,一文吃透 HTML 表单编程与交互
前端
袁煦丞8 分钟前
JuiceSSH你的口袋里的Linux操控台:cpolar内网穿透实验室第530个成功挑战
前端·程序员·远程工作
鹏多多12 分钟前
深入解析vue的transition过渡动画使用和优化
前端·javascript·vue.js
程序员小续24 分钟前
React 源码解读流程:从入口到渲染的全链路揭秘
前端·javascript·面试
江城开朗的豌豆28 分钟前
React key的隐藏技能:key改变时究竟发生了什么?
前端·javascript·react.js