正则表达式的定义和使用
定义:是一种匹配模式,用于匹配字符串中字符组合
作用:表单验证(匹配)、过滤敏感词(替换)、字符串中提取我们想要的部分(提取)
使用分为两步:
1.定义正则表达式
2.检测查找是否匹配
语法:
案例:
注意 查找方法有两种 重点test()
<script>let str = '哈哈嘻嘻可可爱爱'// 1.定义正则表达式const aa = /嘻嘻/// 2.推荐:使用test方法查找 结果返回的是布尔值 返回true或者falseconsole.log(aa.test(str))// 3.使用exec方法查找 结果返回的是数组 有结果返回数组 没有结果返回nullconsole.log(aa.exec(str));</script>
元字符(特殊字符)
以下通过一个例子理解元字符和普通字符的区别
在匹配时,如果是匹配的为英文字符。abcdefghijklmn…z,此时使用普通字符就很麻烦,要写abcdefghijklmn…z,可以直接用元字符来替代 即:[a-z]
边界符
^ 以xxxx开头
$ 以xxxx结尾
属于精确匹配
<script>// 正则表达式直接使用的方法:console.log(/哈/.test('哈'))console.log(/哈/.test('哈哈'))console.log(/哈/.test('二哈'))// 边界符console.log(/哈$/.test('哈'))console.log(/^哈$/.test('哈'))console.log(/哈$/.test('二哈'))最需要注意的 精确匹配 所以是false 读作:以哈开头,以哈结尾 这个哈是同一个哈console.log(/^哈$/.test('二哈'));</script>
量词
注意:把这里的重复理解为出现即可!
<script>console.log('**********************')// * 只能有哈 出现0次或者更多次console.log(/^哈*$/.test('')) // 需要注意trueconsole.log(/^哈*$/.test('哈')) //trueconsole.log(/^哈*$/.test('哈哈哈')) //trueconsole.log(/^哈*$/.test('二哈')) //falseconsole.log(/^哈*$/.test('二哈很傻')) //falseconsole.log(/^哈*$/.test('哈很啥')) //false// 以ha开头 并且重复哈多个 在以哈结尾 所以只能有哈console.log(/^哈*$/.test('哈很哈')) //flaseconsole.log('++++++++++++++++++++++++++++')// + 出现1次或者多次console.log(/^哈+$/.test('')) // 注意:falseconsole.log(/^哈+$/.test('哈')) //trueconsole.log(/^哈+$/.test('哈哈哈')) //trueconsole.log(/^哈+$/.test('二哈')) //falseconsole.log(/^哈+$/.test('二哈很傻')) //falseconsole.log(/^哈+$/.test('哈很啥')) //falseconsole.log(/^哈+$/.test('哈很哈')) //flaseconsole.log('???????????????????????????')// ? 出现0次或者1次console.log(/^哈?$/.test('')) //trueconsole.log(/^哈?$/.test('哈')) //trueconsole.log(/^哈?$/.test('哈哈')) //falseconsole.log(/^哈?$/.test('二哈')) //falseconsole.log(/^哈?$/.test('二哈很傻')) //falseconsole.log(/^哈?$/.test('哈很啥')) //falseconsole.log(/^哈?$/.test('哈很哈')) //flaseconsole.log('{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}{n}')//{n} 出现n次console.log(/^哈{4}$/.test(''))console.log(/^哈{4}$/.test('哈'))console.log(/^哈{4}$/.test('哈哈'))console.log(/^哈{4}$/.test('哈哈哈'))console.log(/^哈{4}$/.test('哈哈哈哈')) //true 其余为falseconsole.log('{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}{n,}')//{n,} 出现n次或者更多次同理//{n,m} 出现n到m次</script>
案例:表单验证 填写验证码,当表单失去焦点就开始验证,如果符合正则规则就在span中添加right类,否则添加error类。
注意:使用classList,后面的样式会覆盖前面的样式;而使用className,重复的类名实现覆盖 进而达到样式切换自如
<style>span {display: inline-block;width: 250px;height: 30px;vertical-align: middle;line-height: 30px;padding-left: 15px;}.error {color: red;background: url(./images/error1.png) no-repeat left center;}.right {color: green;background: url(./images/right.png) no-repeat left center;}</style>
<input type="text"><span></span><script>const reg = /^[a-zA-Z0-9-_]{6,16}$/const input = document.querySelector('input')const span = input.nextElementSiblinginput.addEventListener('blur', function () {if (reg.test(this.value)) {span.innerHTML = '输入正确'span.className = 'right'// 根据样式顺序 后面的样式会覆盖前面的,因此使用获取类名// span.classList.add('right')} else {span.innerHTML = '请输入6~16位的英文数字下划线'span.className = 'error'// span.classList.add('error')}})</script>
复杂的正则细解
/^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8 \d |9[0-35-9])\d{8}$ /
^$表示以什么开头 以什么结尾
1 占了一位
\d 表示0-9任意一个数字
(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9]) 小括号中 有或 表示3之后任意一个数字或者 4 之后5-9任意一个数字 或者 5 之后0-3,5-9任意一个数字 或者6 之后567之间任一个数字 7 之后0-8任一个数字 或者8 之后0-9任意一个数字 或者 9 之后0-3,5-9之间任一个数字 也就是这里占两位
\d{8} 从0-9之间8位任意数字
字符类
1)为什么叫字符类,是因为[]中有个 - 连字符
使用连字符 - 表示一个范围
[a-z] 表示 a 到 z 26个英文字母都可
[a-zA-Z] 大小写都可以
[0-9] 表示 0~9 的数字都可
也就是说:[] n选1 或者多个 主要是看有没有"“^$”",如果有的话,就是n选1;没有则是n选m(或n)
//字符类 n选一console.log(/[abc]/.test('a')) //trueconsole.log(/[abc]/.test('abc')) //trueconsole.log(/^[abc]$/.test('a')) //trueconsole.log(/^[abc]$/.test('b')) //trueconsole.log(/^[abc]$/.test('ab')) //加了开头结尾 只能有一个 falseconsole.log(/^[abc]{2}$/.test('ab')) //true 出现2个//字符类[a-z] 只选一个console.log(/^[a-z]$/.test('p'))console.log(/^[A-Z]$/.test('p')) //区分大小写// 字符类结合量词console.log(/^[0-9a-zA-Z]$/.test('p'))console.log(/^[0-9][0-9]{4,}$/.test(10000))//true
- 取反字符
[^a-z] 表示除了小写英文字母之外的一个字符
//表示除了小子字母其他都为true 在正则表达式中的称为开头 中括号中的为取反符号console.log(/[^a-z]/.test('A'))//true
修饰符+过滤敏感词
修饰符附加在正则表达式之后
i 是单词 ignore 的缩写,匹配时字母不区分大小写
g 是单词 global 的缩写,顾名思义,是全局的意思,全局搜索满足正则表达式的结果
案例:
<script>console.log(/^java$/i.test('JAVA')) //trueconst str = 'java棒,JAVA好'// 在全局搜索 并且忽略大小写 并且把字母更换为其他文字(全局更换)// const re = str.replace(/java/ig, '前端')const re = str.replace(/java|JAVA/g, '前端')console.log(re);</script>
这里有个好奇的地方,不知道大家好奇不 就是我发现,下面代码中tx.value不是字符串吗,怎么可以调用replace方法呢,后来我查到资料,说:js的字符串可以通过一些内置的包装对象来访问其方法和属性。也就是:当我们尝试使用字符串的时候,JavaScript引擎会自动将原始字符串值临时转换为一个对应的包装对象(在这种情况下是 String 对象),然后在这个包装对象上调用方法。方法执行完成后,结果会被返回,而包装对象本身则会被丢弃。这个过程被称为装箱或自动包装。
<textarea name="" id="" cols="30" rows="10"></textarea><button>发布</button><div></div><script>const tx = document.querySelector('textarea')const btn = document.querySelector('button')const div = document.querySelector('div')btn.addEventListener('click', function () {// 死记硬背// console.log(tx.value)// replace前面是一句话div.innerHTML = tx.value.replace(/激情|基情/g, '**')console.log(typeof tx.value)})</script>
综合案例
完整页面资源大家可以直接下载
注册页面主要分为
①发送验证码模块
②各个表单验证模块
③勾选已经同意模块
④下一步验证全部模块,只要有一个input验证不通过就不同意提交
第一部分我们需要将页面设计成当时间达到的时候,因为是短信验证码,所以我们换成重新获取;又因为短信验证码的内容是需要与后台交互的 所以这里先不做
这里给的页面内容很多,听老师说直接我们对哪个表单设计,直接通过检查找到即可,但我还是怕看不懂,还将注册页面的css和html仔细分析了一下,因为怕后面整js的时候出现卡顿的情况,不过后来在整完css和html后,重新整js,发现不用弄我的那一套操作,大家可以按照老师说的!需要对哪一个表单设计就检查一下,找到对应的表单!
注册页面模块:
发送短信验证模块:
// 发送短信验证模块// 1.获取元素 对谁设计就获取谁const code = document.querySelector('.code')let flag = true //节流阀 也就是时间不到就不能点code.addEventListener('click', function () {// 2.想到获取元素之后,是为了让他变成其他文字if (flag) {flag = falselet i = 5this.innerHTML = `0${i}秒后重新获取`let timerId = setInterval(function () {i--// 注意这里不能使用this 只有在函数直接子元素中才可以用 上句代码this就可以code.innerHTML = `0${i}秒后重新获取`// 这里注意一定要将if判断语句写在里面 写在定时器外面的话 定时器就会一直减减,根本不会到下面去执行if (i === 0) {clearInterval(timerId)code.innerHTML = '重新获取'flag = true}}, 1000)}})
各个表单验证模块:
用户名称的验证思路是:先获取元素,然后将元素中的值与正则表达式进行匹配,如果不符合规范在下面就会有红色提示!
先准备好正则表达式匹配规则
// 各个表单验证模块// 用户名验证模块const username = document.querySelector('[name="username"]')// 这里需要多次渲染到页面 所以单独写了个函数// 不好理解就死记硬背:因为这样的表单有很多,都是判断值对不对,不对就需要显示红色提示,红色提示需要渲染到页面,所以就用一个函数包装,这样方便其他函数一改名字就可以使用username.addEventListener('change', verifyName)function verifyName () {const span = username.nextElementSiblingconst reg = /^[a-zA-Z0-9-_]{6,10}$/if (!reg.test(username.value)) {span.innerText = '输入不合法,请输入6-10位'return false}span.innerText = ""return true}// 手机号验证const phone = document.querySelector('[name=phone]')phone.addEventListener('change', verifyPhone)function verifyPhone () {const span = phone.nextElementSiblingconst reg = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/if (!reg.test(phone.value)) {span.innerText = '输入不合法,请输入正确的11位手机号码'return fasle}span.innerText = ""return true}// 验证码const codeInput = document.querySelector('[name="code"]')codeInput.addEventListener('change', verifyCode)function verifyCode () {const span = codeInput.nextElementSiblingconst reg = /^\d{6}$/if (!reg.test(codeInput.value)) {span.innerText = '输入不合法,6位数字'return false}span.innerHTML = ""return true}// 密码框const pwd = document.querySelector('[name="password"]')pwd.addEventListener('change', verifyPwd)function verifyPwd () {const span = pwd.nextElementSiblingconst reg = /^[a-zA-Z0-9-_]{6,20}$/if (!reg.test(pwd.value)) {span.innerHTML = '输入不合法,6-20位数字字母符号组成'return false}span.innerHTML = ""return true}
密码的再次验证 只要与之前密码框输入的值不同 就报红
// 密码的再次验证const confirm = document.querySelector('[name="confirm"]')confirm.addEventListener('change', verigyConfirm)function verigyConfirm () {const span = confirm.nextElementSiblingif (confirm.value !== pwd.value) {span.innerHTML = '两次密码输入不一致'return false}span.innerText = ""return true}
判断表单是否填写成功
const queren = document.querySelector('.icon-queren')queren.addEventListener('click', function () {this.classList.toggle('icon-queren2')})const form = document.querySelector('form')form.addEventListener('submit', function (e) {if (!queren.classList.contains('icon-queren2')) {alert('请勾选同意协议')e.preventDefault()}// 这就是true和false的作用 为后来表单是否正确填写做验证if (!verifyName()) e.preventDefault()if (!verifyPhone()) e.preventDefault()if (!verifyCode()) e.preventDefault()if (!verifyPwd()) e.preventDefault()if (!verifyConfirm()) e.preventDefault()})
登录模块 有一个tab栏切换 选定指定的标签页来显示或者隐藏下面的页面
<script>// tab栏切换 事件委托const tab_nav = document.querySelector('.tab-nav')const pane = document.querySelectorAll('.tab-pane')tab_nav.addEventListener('click', function (e) {if (e.target.tagName === 'A') {// 取消上一个active 给当前元素添加active类tab_nav.querySelector('.active').classList.remove('active')e.target.classList.add('active')// 先干掉所有人 for循环for (let i = 0; i < pane.length; i++) {pane[i].style.display = 'none'}// 让对应的序号的大pane显示pane[e.target.dataset.id].style.display = 'block'}})//点击提交模块const form = document.querySelector('form')const agree = document.querySelector('[name=agree]')const username = document.querySelector('[name=username]')form.addEventListener('submit', function (e) {e.preventDefault()if (!agree.checked) {return alert('请勾选同意协议')}// 记录用户名到本地存储localStorage.setItem('xtx-uname', username.value)// 跳转到首页location.href = './index.html'})</script>
用户登录或者未登录状态的切换
<script>const li1 = document.querySelector('.xtx_navs li:first-child')const li2 = li1.nextElementSiblingfunction render () {const uname = localStorage.getItem('xtx-uname')if (uname) {li1.innerHTML = `<a href="javascript:;"><i class="iconfont icon-user">${uname}</i></a>`li2.innerHTML = '<a href="javascript:;">退出登录</a>'} else {li1.innerHTML = '<a href="./login.html">请先登录</a>'li2.innerHTML = '<a href="./register.html">免费注册</a>'}}render()</script>