表单验证功能描述
- 发送验证码,5秒后可重新发送,显示重新发送倒数秒数
- 点击注册按钮,验证表单中的数据,如果有不符的,将会出现提示
- 信息全部相符,将用户名存储到本地中,方便其他页面使用
实现效果
表单验证实现步骤
1. 准备阶段
学会使用正则表达式验证表单信息
- 基本语法
const r=/验证内容/
r.test(验证数组) //返回布尔值
r.exec(验证数组) //返回匹配数组(不常用)
/^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/ //手机号正则表达式验证
- 正则表达式分类
代码 | 含义 |
---|---|
^ | 匹配项前,以…开头 |
$ | 匹配向后,以…结尾 |
{n} | 重复出现n次 |
{n,} | 重复出现n次以上 |
{n,m} | 重复出现n到m次 |
[] | 重复出现n次 |
[a-b] | 匹配a到b任意一个,除了换行符 |
\w | 相当于[a-zA-Z0-9],大写为排除 |
\d | 相当于[0-9],大写为排除 |
\s | 匹配空格,大写为排除 |
i | 匹配不区分大小写 |
g | 匹配全局 |
清除表单默认事件
const form = document.querySelector('.xtx-form')
form.addEventListener('submit', function (e) {
e.preventDefault()
})
2. 发送验证码
点击发送验证码按钮发送验证码,计时器倒数5秒,5秒后显示重新发送字样
- 验证码发送后,无法重复点击发送,需要设置flag限制点击:flag开始为true,当进入点击事件时flag设为false开始倒计时,期间如果再次点击,则会进入flag是否为false判断,只有当定时器结束后flag才重新为true
- 需要在点击事件内部定义num,可以使每次点击,num都从5开始倒数
const code = document.querySelector('[data-prop="code"]') //获取验证码位置
let timer //外部设置定时器,方便清除
let flag = true
code.addEventListener('click', function (e) { //使用事件委托绑定点击事件
if (e.target.tagName === 'A') {
e.target.addEventListener('click', function () {
if (flag === false) { //flag限制点击
return
} else {
flag = false
let num = 6
timer = setInterval(function () {
num--
if (num === 0) {
clearInterval(timer)
e.target.innerHTML = '重新发送'
flag = true
return //num为0终止打印
}
e.target.innerHTML = `0${num}秒后重新发送`
}, 1000)
}
})
}
})
3. 表单验证
依次获取各个表单的值使用正则表达式加三元运算符验证,封装各验证函数,最后集中封装起来(做法不唯一)
const name = document.querySelector('[name="username"]')
const phone = document.querySelector('[name="phone"]')
const password = document.querySelector('[name="password"]')
const confirm = document.querySelector('[name="confirm"]')
const code1 = document.querySelector('[name="code"]')
const btn = document.querySelector('.submit')
const msg = document.querySelectorAll('.msg') //找到所有msg位置
// 封装验证函数
function vtyName() { //三元运算符加正则表达式
name.nextElementSibling.innerHTML = /^\w{6,10}$/.test(name.value) ? '' : '用户名只能是6-10位数字,字母,下划线'
}
function vtyPhone() {
phone.nextElementSibling.innerHTML = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/.test(phone.value) ? '' : '请输入正确的手机号'
}
function vtyMsg() {
code1.nextElementSibling.innerHTML = /^\d{6}$/.test(code1.value) ? '' : '请输入正确的验证码'
}
function vtyPassword() {
password.nextElementSibling.innerHTML = /^\w{6,20}$/.test(password.value) ? '' : '密码只能是6-20位数字,字母,下划线'
}
function vtyConfirm() {
confirm.nextElementSibling.innerHTML = password.value === confirm.value ? '' : '两次密码输入不一致'
}
function vtyAll() { //封装各验证函数
vtyName()
vtyPhone()
vtyMsg()
vtyPassword()
vtyConfirm()
}
4. 同意阅读协议
1.点击注册按钮,检查同意阅读协议是否勾选,是,则开始进行表单验证,通过显示注册成功。否,则弹出提示框
function vtyAgree() {
if (agree.classList.contains('icon-queren2')) { //agree存在类名icon-queren2时为点击过,也可以使用checkbox验证
vtyAll()
for (let i = 0; i < msg.length; i++) {
if (msg[i].innerHTML != '') { //msg如果有不为''的,则没有通过验证
return
}
}
alert('注册成功')
localStorage.setItem('username', name.value)
form.reset()
} else {
alert('请阅读并同意《用户服务协议》')
}
}
btn.addEventListener('click', function () {
vtyAgree()
})
2.提交完表单信息重置,并将用户名存储到本地中
localStorage.setItem('username', name.value)
form.reset()
完整实例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>小兔鲜儿 - 新鲜 惠民 快捷!</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<style>
.xtx-wrapper {
background: #f5f5f5;
line-height: 1.4;
}
.xtx-wrapper .container {
width: 1240px;
margin: 0 auto;
padding: 50px 0;
}
.xtx-card {
width: 100%;
height: 800px;
background: #fff;
}
.xtx-card h3 {
font-size: 26px;
font-weight: normal;
color: #999999;
padding-left: 50px;
height: 180px;
line-height: 180px;
}
.xtx-form {
padding-left: 460px;
}
.xtx-form .xtx-form-item {
position: relative;
padding-bottom: 24px;
}
.xtx-form .xtx-form-item .msg {
color: #ff4d4f;
position: absolute;
left: 2px;
bottom: 2px;
}
.xtx-form .xtx-form-item.pl50 {
padding-left: 40px;
cursor: pointer;
}
.xtx-form .xtx-form-item span.iconfont {
position: absolute;
left: 15px;
top: 13px;
color: #666;
font-size: 18px;
}
.xtx-form .xtx-form-item i {
color: #27BA9C;
font-size: 14px;
}
.xtx-form .xtx-form-item input {
width: 300px;
height: 50px;
border: 1px solid #e4e4e4;
padding-left: 40px;
}
.xtx-form .xtx-form-item.error input {
border-color: #ff4d4f;
}
.xtx-form .xtx-form-item input::placeholder {
color: #cccccc !important;
}
.xtx-form .xtx-form-item .submit {
width: 300px;
height: 50px;
background: #27BA9B;
border-radius: 4px;
display: block;
font-size: 16px;
color: #fff;
text-align: center;
line-height: 50px;
cursor: pointer;
}
.xtx-form .xtx-form-item .code {
position: absolute;
left: 190px;
top: 16px;
width: 100px;
color: #27BA9B;
text-align: right;
}
.xtx-form .xtx-form-item .code.ing {
color: #cccccc;
}
.xtx-steps {
display: flex;
justify-content: space-between;
width: 720px;
height: 96px;
margin: 0 auto;
}
.xtx-steps .item {
position: relative;
width: 48px;
height: 48px;
}
.xtx-steps .item .text {
text-align: center;
width: 120px;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 63px;
color: #999;
}
.xtx-steps .item .step {
border: 2px solid #e4e4e4;
color: #ccc;
background: #fff;
border-radius: 50%;
line-height: 46px;
text-align: center;
font-size: 28px;
z-index: 999;
display: block;
position: relative;
}
.xtx-steps .item::after,
.xtx-steps .item::before {
content: "";
position: absolute;
top: 23px;
left: 24px;
height: 2px;
background: #e4e4e4;
width: 120px;
}
.xtx-steps .item::after {
transform: translateX(-100%);
}
.xtx-steps .item:first-child::after {
display: none;
}
.xtx-steps .item:last-child::before {
display: none;
}
.xtx-steps .item.active .text {
color: #27BA9B;
}
.xtx-steps .item.active .step {
background: #27BA9B;
color: #fff;
border-color: #27BA9B;
}
.xtx-steps .item.active::after,
.xtx-steps .item.active::before {
content: "";
background: #27BA9B;
}
.xtx-form-label {
padding-left: 360px;
margin-top: 80px;
}
.xtx-form-label .xtx-form-item {
position: relative;
padding-bottom: 24px;
display: flex;
}
.xtx-form-label .xtx-form-item label {
width: 100px;
padding-right: 15px;
text-align: right;
font-size: 16px;
height: 50px;
line-height: 50px;
color: #999;
}
.xtx-form-label .xtx-form-item input {
width: 300px;
height: 50px;
border: 1px solid #e4e4e4;
padding-left: 10px;
}
.xtx-form-label .xtx-form-item input::placeholder {
color: #cccccc !important;
}
.xtx-form-label .xtx-form-item input:read-only {
background: #f5f5f5;
color: #999;
}
.xtx-form-label .xtx-form-item .submit {
width: 300px;
height: 50px;
background: #27BA9B;
border-radius: 4px;
display: block;
font-size: 16px;
color: #fff;
text-align: center;
line-height: 50px;
}
.xtx-form-label .xtx-form-item .captcha {
line-height: 50px;
height: 50px;
}
.xtx-form-label .xtx-form-item .captcha img {
width: 134px;
height: 50px;
}
.xtx-form-label .xtx-form-item .captcha a {
color: #27BA9B;
}
.xtx-form-label .xtx-form-item .code {
position: absolute;
left: 310px;
top: 16px;
color: #27BA9B;
}
.xtx-form-label .xtx-form-item .code.ing {
color: #cccccc;
}
.xtx-success-box {
padding-top: 250px;
text-align: center;
color: #999999;
}
.xtx-success-box .iconfont {
font-size: 80px;
color: #1DC779;
}
.xtx-success-box .tit {
font-size: 20px;
padding: 20px 0;
}
.xtx-success-box .desc {
font-size: 16px;
padding-bottom: 20px;
}
.xtx-success-box .btn {
width: 300px;
height: 50px;
background: #27BA9B;
border-radius: 4px;
display: block;
font-size: 16px;
color: #fff;
text-align: center;
line-height: 50px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class="xtx-wrapper">
<div class="container">
<!-- 卡片 -->
<div class="xtx-card">
<h3>新用户注册</h3>
<form class="xtx-form">
<div data-prop="username" class="xtx-form-item">
<span class="iconfont icon-zhanghao"></span>
<input name="username" type="text" placeholder="设置用户名称">
<span class="msg"></span>
</div>
<div data-prop="phone" class="xtx-form-item">
<span class="iconfont icon-shouji"></span>
<input name="phone" type="text" placeholder="输入手机号码 ">
<span class="msg"></span>
</div>
<div data-prop="code" class="xtx-form-item">
<span class="iconfont icon-zhibiaozhushibiaozhu"></span>
<input name="code" type="text" placeholder="短信验证码">
<span class="msg"></span>
<a class="code" href="javascript:;" aria-disabled="true">发送验证码</a>
</div>
<div data-prop="password" class="xtx-form-item">
<span class="iconfont icon-suo"></span>
<input name="password" type="password" placeholder="设置6至20位字母、数字和符号组合">
<span class="msg"></span>
</div>
<div data-prop="confirm" class="xtx-form-item">
<span class="iconfont icon-suo"></span>
<input name="confirm" type="password" placeholder="请再次输入上面密码">
<span class="msg"></span>
</div>
<div class="xtx-form-item pl50">
<i class="iconfont icon-queren"></i>
已阅读并同意<i>《用户服务协议》</i>
</div>
<div class="xtx-form-item">
<button class="submit">下一步</button>
<!-- <a class="submit" href="javascript:;">下一步</a> -->
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 清除表单默认事件
const form = document.querySelector('.xtx-form')
form.addEventListener('submit', function (e) {
e.preventDefault()
})
// 发送验证码
const code = document.querySelector('[data-prop="code"]')
let timer
let flag = true
code.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
e.target.addEventListener('click', function () {
if (flag === false) {
return
} else {
flag = false
let num = 6
timer = setInterval(function () {
num--
if (num === 0) {
clearInterval(timer)
e.target.innerHTML = '重新发送'
flag = true
return
}
e.target.innerHTML = `0${num}秒后重新发送`
}, 1000)
}
})
}
})
// 同意用户协议
const agree = document.querySelector('.xtx-form-item i')
agree.addEventListener('click', function () {
agree.classList.toggle('icon-queren2')
})
// 表单验证
const name = document.querySelector('[name="username"]')
const phone = document.querySelector('[name="phone"]')
const password = document.querySelector('[name="password"]')
const confirm = document.querySelector('[name="confirm"]')
const code1 = document.querySelector('[name="code"]')
const btn = document.querySelector('.submit')
const msg = document.querySelectorAll('.msg')
// 封装验证函数
function vtyName() {
name.nextElementSibling.innerHTML = /^\w{6,10}$/.test(name.value) ? '' : '用户名只能是6-10位数字,字母,下划线'
}
function vtyPhone() {
phone.nextElementSibling.innerHTML = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/.test(phone.value) ? '' : '请输入正确的手机号'
}
function vtyMsg() {
code1.nextElementSibling.innerHTML = /^\d{6}$/.test(code1.value) ? '' : '请输入正确的验证码'
}
function vtyPassword() {
password.nextElementSibling.innerHTML = /^\w{6,20}$/.test(password.value) ? '' : '密码只能是6-20位数字,字母,下划线'
}
function vtyConfirm() {
confirm.nextElementSibling.innerHTML = password.value === confirm.value ? '' : '两次密码输入不一致'
}
function vtyAll() {
vtyName()
vtyPhone()
vtyMsg()
vtyPassword()
vtyConfirm()
}
function vtyAgree() {
if (agree.classList.contains('icon-queren2')) {
vtyAll()
for (let i = 0; i < msg.length; i++) {
if (msg[i].innerHTML != '') {
return
}
}
alert('注册成功')
localStorage.setItem('username', name.value)
form.reset()
} else {
alert('请阅读并同意《用户服务协议》')
}
}
btn.addEventListener('click', function () {
vtyAgree()
})
</script>
</body>
</html>