提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、正则表达式
- 正则基本使用
- 元字符
- 边界符
- 量词
- 范围
- 字符类
- 二、替换和修饰符
- 三、正则插件
- change 事件
- 判断是否有类
- 四、案例举例
- 学生就业信息表
- 用户注册界面
- 用户登录界面
- 顶部导航显示登录人信息
- 放大镜效果
前言
- 正则表达式
- 综合案例
- 阶段案例
一、正则表达式
正则表达式(Regular Expression)是一种字符串匹配的模式(规则)
使用场景:
- 例如 验证表单:手机号表单要求用户只能输入11位的数字 (匹配)
- 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等
正则基本使用
-
定义规则
const reg = /表达式/
- 其中
/ /
是正则表达式字面量 - 正则表达式也是
对象
- 其中
-
使用正则
test()方法
用来查看正则表达式与指定的字符串是否匹配- 如果正则表达式与指定的字符串匹配 ,返回
true
,否则false
<body><script>// 正则表达式的基本使用const str = 'web前端开发'// 1. 定义规则const reg = /web/// 2. 使用正则 test()console.log(reg.test(str)) // true 如果符合规则匹配上则返回trueconsole.log(reg.test('java开发')) // false 如果不符合规则匹配上则返回 false</script>
</body>
元字符
- 普通字符:
- 大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。
- 普通字符只能够匹配字符串中与它们相同的字符。
- 比如,规定用户只能输入英文26个英文字母,普通字符的话 /[abcdefghijklmnopqrstuvwxyz]/
- 元字符(特殊字符)
- 是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
- 比如,规定用户只能输入英文26个英文字母,换成元字符写法: /[a-z]/
边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
如果 ^ 和 $ 在一起,表示必须是精确匹配
<body><script>// 元字符之边界符// 1. 匹配开头的位置 ^const reg = /^web/console.log(reg.test('web前端')) // trueconsole.log(reg.test('前端web')) // falseconsole.log(reg.test('前端web学习')) // falseconsole.log(reg.test('we')) // false// 2. 匹配结束的位置 $const reg1 = /web$/console.log(reg1.test('web前端')) // falseconsole.log(reg1.test('前端web')) // trueconsole.log(reg1.test('前端web学习')) // falseconsole.log(reg1.test('we')) // false // 3. 精确匹配 ^ $const reg2 = /^web$/console.log(reg2.test('web前端')) // falseconsole.log(reg2.test('前端web')) // falseconsole.log(reg2.test('前端web学习')) // falseconsole.log(reg2.test('we')) // false console.log(reg2.test('web')) // trueconsole.log(reg2.test('webweb')) // flase </script>
</body>
量词
量词用来设定某个模式重复次数
注意: 逗号左右两侧千万不要出现空格
<body><script>// 元字符之量词// 1. * 重复次数 >= 0 次const reg1 = /^w*$/console.log(reg1.test('')) // trueconsole.log(reg1.test('w')) // trueconsole.log(reg1.test('ww')) // trueconsole.log('-----------------------')// 2. + 重复次数 >= 1 次const reg2 = /^w+$/console.log(reg2.test('')) // falseconsole.log(reg2.test('w')) // trueconsole.log(reg2.test('ww')) // trueconsole.log('-----------------------')// 3. ? 重复次数 0 || 1 const reg3 = /^w?$/console.log(reg3.test('')) // trueconsole.log(reg3.test('w')) // trueconsole.log(reg3.test('ww')) // falseconsole.log('-----------------------')// 4. {n} 重复 n 次const reg4 = /^w{3}$/console.log(reg4.test('')) // falseconsole.log(reg4.test('w')) // flaseconsole.log(reg4.test('ww')) // falseconsole.log(reg4.test('www')) // trueconsole.log(reg4.test('wwww')) // falseconsole.log('-----------------------')// 5. {n,} 重复次数 >= n const reg5 = /^w{2,}$/console.log(reg5.test('')) // falseconsole.log(reg5.test('w')) // falseconsole.log(reg5.test('ww')) // trueconsole.log(reg5.test('www')) // trueconsole.log('-----------------------')// 6. {n,m} n =< 重复次数 <= mconst reg6 = /^w{2,4}$/console.log(reg6.test('w')) // falseconsole.log(reg6.test('ww')) // trueconsole.log(reg6.test('www')) // trueconsole.log(reg6.test('wwww')) // trueconsole.log(reg6.test('wwwww')) // false// 7. 注意事项: 逗号两侧千万不要加空格否则会匹配失败</script>
范围
表示字符的范围,定义的规则限定在某个范围,比如只能是英文字母,或者数字等等,用表示范围
<body><script>// 元字符之范围 [] // 1. [abc] 匹配包含的单个字符, 多选1const reg1 = /^[abc]$/console.log(reg1.test('a')) // trueconsole.log(reg1.test('b')) // trueconsole.log(reg1.test('c')) // trueconsole.log(reg1.test('d')) // falseconsole.log(reg1.test('ab')) // false// 2. [a-z] 连字符 单个const reg2 = /^[a-z]$/console.log(reg2.test('a')) // trueconsole.log(reg2.test('p')) // trueconsole.log(reg2.test('0')) // falseconsole.log(reg2.test('A')) // false// 想要包含小写字母,大写字母 ,数字const reg3 = /^[a-zA-Z0-9]$/console.log(reg3.test('B')) // trueconsole.log(reg3.test('b')) // trueconsole.log(reg3.test(9)) // trueconsole.log(reg3.test(',')) // flase// 用户名可以输入英文字母,数字,可以加下划线,要求 6~16位const reg4 = /^[a-zA-Z0-9_]{6,16}$/console.log(reg4.test('abcd1')) // false console.log(reg4.test('abcd12')) // trueconsole.log(reg4.test('ABcd12')) // trueconsole.log(reg4.test('ABcd12_')) // true// 3. [^a-z] 取反符const reg5 = /^[^a-z]$/console.log(reg5.test('a')) // false console.log(reg5.test('A')) // trueconsole.log(reg5.test(8)) // true</script>
</body>
字符类
某些常见模式的简写方式,区分字母和数字
日期格式 : /^\d{4}-\d{1,2}-\d{1,2}$/
二、替换和修饰符
replace 替换方法,可以完成字符的替换
字符串.replace(/正则表达式/,‘替换的文本’)
<body><script>// 替换和修饰符const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'// 1. 替换 replace 需求:把前端替换为 web// 1.1 replace 返回值是替换完毕的字符串// const strEnd = str.replace(/前端/, 'web') 只能替换一个</script>
</body>
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
<body><script>// 替换和修饰符const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'// 1. 替换 replace 需求:把前端替换为 web// 1.1 replace 返回值是替换完毕的字符串// const strEnd = str.replace(/前端/, 'web') 只能替换一个// 2. 修饰符 g 全部替换const strEnd = str.replace(/前端/g, 'web')console.log(strEnd) </script>
</body>
三、正则插件
change 事件
给input注册 change 事件,值被修改并且失去焦点后触发
判断是否有类
元素.classList.contains() 看看有没有包含某个类,如果有则返回true,没有则返回false
四、案例举例
学生就业信息表
map、join、localStorage
<script>//1.获取元素const uname = document.querySelector('.uname')const age = document.querySelector('.age')const gender = document.querySelector('.gender')const salary = document.querySelector('.salary')const city = document.querySelector('.city')const info = document.querySelector('.info')const items = document.querySelectorAll('[name]')let arr = []//form提交事件(数据更新渲染函数)info.addEventListener('submit', function (e) {//阻止默认行为e.preventDefault()//判断内容是否为空for (let i = 0; i < items.length; i++) {if (items[i].value === '') { //return alert('输入不能为空')}}//数据替换const data = {stuId: arr.length + 1,uname: uname.value,age: age.value,gender: gender.value,salary: salary.value,city: city.value,}arr.push(data)localStorage.setItem('data', JSON.stringify(arr))//新数据渲染到下面表格render()//清空text填写原有数据this.reset()})function render() {let new_data = arr.map(function (e, index) { //arr.map(function)(e,index){})return `<tr><td>${e.stuId}</td><td>${e.uname}</td><td>${e.age}</td><td>${e.gender}</td><td>${e.salary}</td><td>${e.city}</td><td><a href="javascript:" data-id=${index}>删除</a></td></tr> `})tbody.innerHTML = new_data.join('');}//del删除事件(借助自定义属性)const tbody = document.querySelector('tbody')tbody.addEventListener('click', function (e) {if (e.target.tagName === 'A') {arr.splice(e.target.dataset.id, 1) //arr render里面的new_data是添加在tbody里面localStorage.removeItem('data', JSON.stringify(arr[e.target.dataset.id]))render()localStorage.setItem('data', JSON.stringify(arr))}})</script>
用户注册界面
验证码模块;用户名、手机号、密码等验证模块;同意服务协议模块;表达提交模块。
<script>(function () {// 1. 发送短信验证码模块const code = document.querySelector('.code')let flag = true // 通过一个变量来控制 节流阀 // 1.1 点击事件code.addEventListener('click', function () {if (flag) {// 取反了,不能马上第二次点击flag = falselet i = 5// 点击完毕之后立马触发code.innerHTML = `0${i}秒后重新获取`// 开启定时器let timerId = setInterval(function () {i--code.innerHTML = `0${i}秒后重新获取`if (i === 0) {// 清除定时器clearInterval(timerId)// 从新获取code.innerHTML = `重新获取`// 到时间了,可以开启 flag了flag = true}}, 1000)}})})();// 2. 验证的是用户名// 2.1 获取用户名表单const username = document.querySelector('[name=username]')// 2.2 使用change事件 值发生变化的时候username.addEventListener('change', verifyName)// 2.3 封装verifyName函数function verifyName() {// console.log(11)const span = username.nextElementSibling// 2.4 定规则 用户名const reg = /^[a-zA-Z0-9-_]{6,10}$/if (!reg.test(username.value)) {// console.log(11)span.innerText = '输入不合法,请输入6~10位'return false}// 2.5 合法的 就清空spanspan.innerText = ''return true}// 3. 验证的是手机号// 2.1 获取手机表单const phone = document.querySelector('[name=phone]')// 2.2 使用change事件 值发生变化的时候phone.addEventListener('change', verifyPhone)// 2.3 verifyPhonefunction verifyPhone() {// console.log(11)const span = phone.nextElementSibling// 2.4 定规则 用户名const 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)) {// console.log(11)span.innerText = '输入不合法,请输入正确的11位手机号码'return false}// 2.5 合法的 就清空spanspan.innerText = ''return true}// 4. 验证的是验证码// 4.1 获取验证码表单const codeInput = document.querySelector('[name=code]')//4.2 使用change事件 值发生变化的时候codeInput.addEventListener('change', verifyCode)// 4.3 verifyPhonefunction verifyCode() {// console.log(11)const span = codeInput.nextElementSibling// 4.4 定规则 验证码const reg = /^\d{6}$/if (!reg.test(codeInput.value)) {// console.log(11)span.innerText = '输入不合法,6 位数字'return false}// 4.5 合法的 就清空spanspan.innerText = ''return true}// 5. 验证的是密码框// 5.1 获取密码表单const password = document.querySelector('[name=password]')//5.2 使用change事件 值发生变化的时候password.addEventListener('change', verifyPwd)// 5.3 verifyPhonefunction verifyPwd() {// console.log(11)const span = password.nextElementSibling// 5.4 定规则 密码const reg = /^[a-zA-Z0-9-_]{6,20}$/if (!reg.test(password.value)) {// console.log(11)span.innerText = '输入不合法,6~20位数字字母符号组成'return false}// 5.5 合法的 就清空spanspan.innerText = ''return true}// 6. 密码的再次验证// 6.1 获取再次验证表单const confirm = document.querySelector('[name=confirm]')//6.2 使用change事件 值发生变化的时候confirm.addEventListener('change', verifyConfirm)// 6.3 verifyPhonefunction verifyConfirm() {// console.log(11)const span = confirm.nextElementSibling// 6.4 当前表单的值不等于 密码框的值就是错误的if (confirm.value !== password.value) {// console.log(11)span.innerText = '两次密码输入不一致'return false}// 6.5 合法的 就清空spanspan.innerText = ''return true}// 7. 我同意const queren = document.querySelector('.icon-queren')queren.addEventListener('click', function () {// 切换类 原来有的就删掉,原来没有就添加this.classList.toggle('icon-queren2')})// 8. 提交模块const form = document.querySelector('form')form.addEventListener('submit', function (e) {// 判断是否勾选我同意模块 ,如果有 icon-queren2说明就勾选了,否则没勾选if (!queren.classList.contains('icon-queren2')) {alert('请勾选同意协议')// 阻止提交e.preventDefault()}// 依次判断上面的每个框框 是否通过,只要有一个没有通过的就阻止// console.log(verifyName())if (!verifyName()) e.preventDefault()if (!verifyPhone()) e.preventDefault()if (!verifyCode()) e.preventDefault()if (!verifyPwd()) e.preventDefault()if (!verifyConfirm()) e.preventDefault()})</script>
用户登录界面
tab栏切换;表单提交模块并存储localStorage;location跳转首页
<script>// 1. tab栏切换 事件委托const tab_nav = document.querySelector('.tab-nav')const pane = document.querySelectorAll('.tab-pane')// 1.1 事件监听tab_nav.addEventListener('click', function (e) {if (e.target.tagName === 'A') {// 取消上一个activetab_nav.querySelector('.active').classList.remove('active')// 当前元素添加activee.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>// 1、 获取第一个小liconst li1 = document.querySelector('.xtx_navs li:first-child')const li2 = li1.nextElementSibling// 2. 最好做个渲染函数 因为退出登录需要重新渲染function render() {// 2.1 读取本地存储的用户名const uname = localStorage.getItem('xtx-uname')// console.log(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() // 调用函数// 2. 点击退出登录模块li2.addEventListener('click', function () {// 删除本地存储的数据localStorage.removeItem('xtx-uname')// 重新渲染render()})</script>
放大镜效果
<script>
//三个图的故事(function () {// 1. 获取三个盒子// 2. 小盒子 图片切换效果const small = document.querySelector('.small')// 中盒子const middle = document.querySelector('.middle')// 大盒子const large = document.querySelector('.large')// 2. 事件委托small.addEventListener('mouseover', function (e) {if (e.target.tagName === 'IMG') {// console.log(111)// 排他 干掉以前的 active li 上面this.querySelector('.active').classList.remove('active')// 当前元素的爸爸添加 activee.target.parentNode.classList.add('active')// 拿到当前小图片的 src// console.log(e.target.src)// 让中等盒子里面的图片,src 更换为 小图片srcmiddle.querySelector('img').src = e.target.src// 大盒子更换背景图片large.style.backgroundImage = `url(${e.target.src})`}})// 3. 鼠标经过中等盒子, 显示隐藏 大盒子middle.addEventListener('mouseenter', show)middle.addEventListener('mouseleave', hide)let timeId = null// 显示函数 显示大盒子function show() {// 先清除定时器clearTimeout(timeId)large.style.display = 'block'}// 隐藏函数 隐藏大盒子function hide() {timeId = setTimeout(function () {large.style.display = 'none'}, 200)}// 4. 鼠标经过大盒子, 显示隐藏 大盒子large.addEventListener('mouseenter', show)large.addEventListener('mouseleave', hide)// 5. 鼠标经过中等盒子,显示隐藏 黑色遮罩层const layer = document.querySelector('.layer')middle.addEventListener('mouseenter', function () {layer.style.display = 'block'})middle.addEventListener('mouseleave', function () {layer.style.display = 'none'})// 6.移动黑色遮罩盒子middle.addEventListener('mousemove', function (e) {// let x = 10, y = 20// console.log(11)// 鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标// console.log(e.pageX)鼠标在页面中的坐标// middle 中等盒子的坐标// console.log(middle.getBoundingClientRect().left)let x = e.pageX - middle.getBoundingClientRect().leftlet y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop// console.log(x, y)// 黑色遮罩移动 在 middle 盒子内 限定移动的距离if (x >= 0 && x <= 400 && y >= 0 && y <= 400) {// 黑色盒子不是一直移动的// 声明2个变量 黑色盒子移动的 mx my变量 let mx = 0, my = 0if (x < 100) mx = 0if (x >= 100 && x <= 300) mx = x - 100if (x > 300) mx = 200if (y < 100) my = 0if (y >= 100 && y <= 300) my = y - 100if (y > 300) my = 200layer.style.left = mx + 'px'layer.style.top = my + 'px'// 大盒子的背景图片要跟随 中等盒子移动 存在的关系是 2倍 large.style.backgroundPositionX = -2 * mx + 'px'large.style.backgroundPositionY = -2 * my + 'px'}})})();</script>