BOM
window对象 ==>包含docment
Browser Object Model
定时器–延时函数
之前学的是间歇函数
让代码延迟执行 仅执行一次
setTimeout(回调函数,等待毫秒数)
消除 clearTimeout(timer)
==> 用于递归时需要进行去除
JS执行机制
单线程 ==> 一个任务结束,才会执行下一个任务
导致渲染慢
如何解决?
Web Worker标准 == 允许JavaScript脚本创建多个线程
因此分出了同步和异步
同步 | 程序的执行顺序和任务的排列顺序一样 |
---|---|
异步 | 当一件事花费很长时间,同时还可以处理其他事情 |
同步任务 | 立马就能执行,都在主线程上执行,形成一个执行栈 |
---|---|
异步任务 | 普通事件,资源加载,定时器等等,添加到任务队列中 |
[!IMPORTANT]
- 先执行执行栈【相当于主车道】中的同步任务
- 异步任务放入任务队列中【应急车道】
- 一旦执行栈中的所有同步任务执行完毕,系统会按次序读取任务队列中的异步任务==> 结束等待状态,进入执行栈,执行
事件循环
进行多线程处理的是,浏览器[宿主环境]而不是JavaScript,
location 对象
拆分并保存了URL的各个部分
常用属性
href | 赋值则会跳转到网址,可配合定时器 |
---|---|
search | 拿地址中’?'后面的信息(表单提交的数据等) |
hash | '#'后面的值 |
补充方法:
reload(布尔值) 若为true,则可以强制刷新
navigator 对象
判断用户使用设备 ==> 跳转到适配页面
history 对象
管理历史记录,前进后退历史页面
相当于浏览器中的前进后退的按钮
back() | 后踢一个页面 |
---|---|
forward() | 前进一个页面 |
go(参数) | 通过参数判断前进后退到哪里 |
本地存储
本地存储数据,读取方便,刷新页面不会丢失
localStorage
永久存储在本地
- 增
setItem(key,value)
- 删
removeItem(key)
- 改
setItem(key,value)
- 获取
getItem(key)
路径:
检查 ==> Application ==> Storage ==> local …
sessionStorage
不同:生命周期为关闭浏览器窗口
若需要存储复杂数据
转换为JSON字符串存储,转换会复杂数据类型获取
JSON.stringify(复杂数据类型) | JSON.parse(key) |
---|
综合案例
学生统计表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>学生就业统计表</title>
<link rel="stylesheet" href="./iconfont/iconfont.css">
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<h1>学生就业统计表</h1>
<form class="info" autocomplete="off">
<input type="text" class="uname" name="uname" placeholder="姓名" />
<input type="text" class="age" name="age" placeholder="年龄" />
<input type="text" class="salary" name="salary" placeholder="薪资" />
<select name="gender" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
<select name="city" class="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="曹县">曹县</option>
</select>
<button class="add">
<i class="iconfont icon-tianjia"></i>添加
</button>
</form>
<div class="title">共有数据<span>0</span>条</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>录入时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!--
<tr>
<td>1</td>
<td>迪丽热巴</td>
<td>23</td>
<td>女</td>
<td>12000</td>
<td>北京</td>
<td>2099/9/9 08:08:08</td>
<td>
<a href="javascript:">
<i class="iconfont icon-shanchu"></i>
删除
</a>
</td>
</tr> -->
</tbody>
</table>
<script>
// const obj = {
// stuId: arr.length + 1,
// uname: uname.value,
// age: 22,
// salary: salary.value,
// gender: gender.value,
// city: city.value,
// time: new Date().toLocaleString(),
// }
//获取对象
const tbody = document.querySelector('tbody')
const info = document.querySelector('.info')
const add = document.querySelector('.add')
const uname = document.querySelector('.uname')
const age = document.querySelector('.age')
const salary = document.querySelector('.salary')
const gender = document.querySelector('.gender')
const city = document.querySelector('.city')
const howmany = document.querySelector('.title span')
const initData = []
// localStorage.setItem('data', JSON.stringify(initData))
const arr = JSON.parse(localStorage.getItem('data'))
render()
//渲染业务
function render() {
//从本地数据中读取数组
//更改为tr的格式
const newArr = arr.map(function (ele, index) {
return `
<td>${ele.stuId}</td>
<td>${ele.uname}</td>
<td>${ele.age}</td>
<td>${ele.gender}</td>
<td>${ele.salary}</td>
<td>${ele.city}</td>
<td>${ele.time}</td>
<td>
<a href="javascript:" data-id="${index}">
<i class="iconfont icon-shanchu"></i>
删除
</a>
</td>
</tr>
`
})
console.log(newArr);
//转化为字符串形式并存储到tbody的innerHTMl中
tbody.innerHTML = newArr.join('')
//渲染一共有几条数据
howmany.innerHTML = arr.length
}
//新增业务
function addMan() {
//点击添加按钮
//1.阻止表单默认提交行为
info.addEventListener('submit', function (e) {
e.preventDefault()
})
//2.判断表单中是否有内容空了,空了则返回提示信息
if (!uname.value || !age.value || !salary.value) {
return alert('输入内容不能为空')
}
//3.将表单的数据写道对象中
//4.将对象追加到arr数组中去
arr.push({
stuId: arr.length + 1,
uname: uname.value,
age: 22,
salary: salary.value,
gender: gender.value,
city: city.value,
time: new Date().toLocaleString()
})
//4.1将arr存储到本地中
localStorage.setItem('data', JSON.stringify(arr))
//5.重新渲染页面
render()
//6.重置表单
info.reset()
}
add.addEventListener('click', function () {
addMan()
})
//删除业务
//1.点击删除按钮 tbody 利用事件委托
tbody.addEventListener('click', function (e) {
//2.判断是否为a
if (e.target.tagName === 'A') {
//3.弹窗,询问是否删除
// let input = +(prompt('是否删除,删除选1,不删除选0'))
if (confirm('您是否要删除这条学生数据')) {
//4.若删除,获取对应对象的dataset值
//5.通过对应的id值来索引下标,删除arr中的对应元素
arr.splice(+(e.target.dataset.id), 1)
//5.1将本地存储数据更新
localStorage.setItem('data', JSON.stringify(arr))
//6.重新渲染页面
render()
}
}
})
</script>
</body>
</html>
可实现
- 渲染页面
- 新增数据
- 删除数据
- 刷新页面不会消失数据,依旧有以前的数据
正则表达式(对象)
用于匹配字符串中字符组合的模式
use:用来查找,替换那些符合正则表达式的文本 ==> 匹配,替换,提取
语法
- 定义规则
/....../
==> 字面量 - 查找
方法
test(字符串) | 返回布尔值 |
---|---|
exec(字符串) | 返回数组或null |
exec()返回的数组中包含的是匹配正则表达式的字符串的相关信息
元字符
具有特殊含义的字符
- 边界符
^---开头 $---结尾 两个一起使用则为精准匹配
- 量词
- 字符类
修饰符
语法位置
/...../修饰符
i | 忽略字母大小写 |
---|---|
g | 匹配所有结果 |
案例
用户验证案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<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>
</head>
<body>
<input type="text">
<span></span>
<script>
//获取对象
const input = document.querySelector('input')
const span = document.querySelector('span')
//书写正则表达式的规则
const rule = /^[a-zA-Z0-9-_]{6,16}$/
//绑定事件
input.addEventListener('blur', function () {
//判断是否符合正则表达式规则
if (rule.test(this.value)) {
span.className = 'right'
// console.log('right');
span.innerHTML = '输入正确'
} else {
span.className = 'error'
// console.log('wrong');
span.innerHTML = '请输入6-16位由英文字母,数字,下划线的字符串'
}
})
</script>
</body>
</html>
综合案例:
页面注册
//获取所有对象
const code = document.querySelector('.code')
//发送验证码模块
//获取对象
//绑定点击事件
let flag = true //控制在倒计时内无法再次点击发送验证码 节流阀
code.addEventListener('click', function () {
if (flag) {
flag = false
let num = 5
code.innerHTML = '5秒后重新获取'
let stop = setInterval(function () {
num--
code.innerHTML = `${num}秒后重新获取`
if (num === 0) {
code.innerHTML = `重新获取`
clearInterval(stop)
//到时间了,可以使节流阀flag打开了
flag = true
}
}, 1000)
}
})
//验证输入内容是否符合模块
//1.用户名模块
const name = document.querySelector('[name=username]')
//1.1绑定事件
name.addEventListener('change', verifyName)
//1.2封装函数
function verifyName() {
// console.log(11);
const tip = name.nextElementSibling
//设定正则表达式
const ruleName = /^[a-zA-Z0-9-_]{6,10}$/
if (!ruleName.test(name.value)) {
tip.innerHTML = '输入有误,请输入6-10位'
return false
}
tip.innerHTML = ''
return true
}
//2.手机号模块
const phone = document.querySelector('[name=phone]')
//1.1绑定事件
phone.addEventListener('change', verifyPhone)
//1.2封装函数
function verifyPhone() {
// console.log(11);
const tip = phone.nextElementSibling
//设定正则表达式
const rulePhone = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
if (!rulePhone.test(phone.value)) {
tip.innerHTML = '输入有误,请输入11位手机号码'
return false
}
tip.innerHTML = ''
return true
}
//3.密码模块
const password = document.querySelector('[name=password]')
//1.1绑定事件
password.addEventListener('change', verifypassword)
//1.2封装函数
function verifypassword() {
// console.log(11);
const tip = password.nextElementSibling
//设定正则表达式
const rulepassword = /^[a-zA-Z0-9-_]{6,20}$/
if (!rulepassword.test(password.value)) {
tip.innerHTML = '输入有误,请输入6-20位字母数字下划线密码'
return false
}
tip.innerHTML = ''
return true
}
//4.验证码模块
const Code = document.querySelector('[name=code]')
//1.1绑定事件
Code.addEventListener('change', verifyCode)
//1.2封装函数
function verifyCode() {
// console.log(11);
const tip = Code.nextElementSibling
//设定正则表达式
const ruleCode = /^\d{6}$/
if (!ruleCode.test(Code.value)) {
tip.innerHTML = '输入有误,请输入6位数字'
return false
}
tip.innerHTML = ''
return true
}
//5.再次密码验证模块
const confirm = document.querySelector('[name=confirm]')
//1.1绑定事件
confirm.addEventListener('change', verifyconfirm)
//1.2封装函数
function verifyconfirm() {
// console.log(11);
const tip = confirm.nextElementSibling
//设定正则表达式
const ruleconfirm = /^\d{6}$/
if (!(confirm.value === password.value)) {
tip.innerHTML = '与上述密码不一致'
return false
}
tip.innerHTML = ''
return true
}
//6.协议模块
//获取对象
const agree = document.querySelector('.icon-queren')
//绑定点击事件
agree.addEventListener('click', function () {
agree.classList.toggle('icon-queren2')
})
//7.全部提交
//获取表单对象
const form = document.querySelector('form')
//添加提交事件监听器
form.addEventListener('submit', function (e) {
//判断是否同意协议
if (!agree.classList.contains('icon-queren2')) {
alert('请勾选同意协议')
//阻止表单默认行为
e.preventDefault()
}
//依次判断其他模块是否输入正确内容
if (!verifyName()) e.preventDefault()
if (!verifyconfirm()) e.preventDefault()
if (!verifyCode()) e.preventDefault()
if (!verifypassword()) e.preventDefault()
if (!verifyPhone()) e.preventDefault()
})
补充知识点:
- input的change事件 ==> 当内容发生变化,且失去焦点,事件触发
- classList有新方法contains(‘类名’) 返回布尔值
登录页面
//1.tab栏切换
//获取对象 -- 事件委托
const tab_nav = document.querySelector('.tab-nav')
const panel = document.querySelectorAll('.tab-pane')
//绑定事件
tab_nav.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
//取消之前的active
tab_nav.querySelector('.active').classList.remove('active')
//增加后来的active
e.target.classList.add('active')
}
//更换对应盒子
//先全部去除
for (let i = 0; i < panel.length; i++) {
panel[i].style.display = 'none'
}
//显示对应需要的盒子
panel[e.target.dataset.id].style.display = 'block'
})
//点击提交事件
const agree = document.querySelector('[name=agree]')
const form = document.querySelector('form')
const username = document.querySelector('[name=username]')
const password = document.querySelector('[name=password]')
//绑定提交事件
form.addEventListener('submit', function (e) {
//阻止提交
e.preventDefault()
//判断是否有同意协议
if (!agree.checked) {
alert('请勾选协议')
}
//将数据存储到本地存储中去
localStorage.setItem('xtx_name', username.value)
localStorage.setItem('xtx_pwd', password.value)
//跳转页面
location.href = 'http://127.0.0.1:5500/webAPI/%E5%85%83%E5%AD%97%E7%AC%A6%E6%A1%88%E4%BE%8B/%E7%BB%BC%E5%90%88%E6%A1%88%E4%BE%8B%E7%B4%A0%E6%9D%90/index.html'
})
首页页面
//获取对象
const li1 = document.querySelector('.xtx_navs li:first-child')
const li2 = li1.nextElementSibling
//封装render函数
function render() {
//获取本地数据
const uname = localStorage.getItem('xtx_name')
//判断是否有用户名数据
if (uname) {
li1.innerHTML = ` <a href="javascript:;">${uname}</a>`
li2.innerHTML = ` <a href="javascript:;">退出登录</a>`
} else {
li1.innerHTML = `<a href="./login.html">请先登录</a>`
li2.innerHTML = ` <a href="./register.html">免费注册</a>`
}
}
//跳转页面后先进行一次渲染
render()
//绑定事件
li2.addEventListener('click', function () {
//删除本地数据
localStorage.removeItem('xtx_name')
//重新渲染
render()
})