1. tab栏切换——排他思想
使用场景: 切换tab栏时,改变选项的选中状态 排他思想:
- 移除上一个选中状态的选中类名
- 为当前元素添加选中类名
//1.tab栏切换
const tabNav = document.querySelector('.tab-nav')
const tabPane = document.querySelectorAll('.tab-pane')
console.log(tabPane)
tabNav.addEventListener('click',function(e){
if(e.target.tagName === 'A'){
//排他,取消上一个元素的active,为当前元素添加active
tabNav.querySelector('.active').classList.remove('active')
e.target.classList.add('active')
for(let i = 0;i<tabPane.length;i++){
tabPane[i].style.display = 'none'
}
tabPane[e.target.dataset.id].style.display = 'block'
}
})
//2.提交模块
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'
})
2. 表单验证
验证表单内容时,建议使用函数,当失去焦点时触发函数。
- 如果不符合要求,则出现提示信息,并 return false 中断程序
- 如果符合要求,则 return true
返回布尔值的原因: 当点击提交时,根据验证函数返回值确定是否阻止提交表单
//1.点击发送验证码
const code = document.querySelector('.code')
let flag = true //通过flag变量来控制是否能够点击 节流阀
code.addEventListener('click', function () {
if (flag) {
//取反,不能马上第二次点击
flag = false
let i = 5
code.innerHTML = '05秒后重新获取'
const timeId = setInterval(function () {
i--
code.innerHTML = `0${i}秒后重新获取`
if (i === 0) {
clearInterval(timeId)
code.innerHTML = `重新获取`
//倒计时结束,可以再次点击
flag = true
}
}, 1000)
}
})
//2.验证用户名
const username = document.querySelector('[name=username]')
username.addEventListener('change', verifyName)
//封装检验函数
function verifyName() {
const msg = username.nextElementSibling
//定义正则,检验用户输入是否符合
const regt = /^[a-zA-Z0-9-_]{6,10}$/.test(username.value)
if (!regt) {
msg.innerHTML = '格式错误,请输入6~10位'
return false
}
msg.innerHTML = ''
return true
}
//3.验证手机号
const phone = document.querySelector('[name=phone]')
phone.addEventListener('change', verifyPhone)
//封装检验函数
function verifyPhone() {
const msg = phone.nextElementSibling
//定义正则,检验用户输入是否符合要求
const regt = /^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)
if (!regt) {
msg.innerHTML = '格式错误,请输入11位手机号'
return false
}
msg.innerHTML = ''
return true
}
//4.验证验证码
const codeInput = document.querySelector('[name=code]')
codeInput.addEventListener('change', verifyCode)
//封装检验函数
function verifyCode() {
const msg = codeInput.nextElementSibling
//定义正则,检验用户输入是否符合要求
const regt = /^\d{6}$/.test(codeInput.value)
if (!regt) {
msg.innerHTML = '格式错误,请输入6位数字'
return false
}
msg.innerHTML = ''
return true
}
//5.验证密码
const password = document.querySelector('[name=password]')
password.addEventListener('change', verifyPassword)
//封装检验函数
function verifyPassword() {
const msg = password.nextElementSibling
//定义正则,检验用户输入是否符合要求
const regt = /^[a-zA-Z0-9-_]{6,20}$/.test(password.value)
if (!regt) {
msg.innerHTML = '格式错误,6-20位数字或字母组成'
return false
}
msg.innerHTML = ''
return true
}
//6.再次验证密码
const confirm = document.querySelector('[name=confirm]')
confirm.addEventListener('change', verifyConfirm)
//封装检验函数
function verifyConfirm() {
const msg = confirm.nextElementSibling
if (confirm.value !== password.value) {
msg.innerHTML = '密码不一致'
return false
}
msg.innerHTML = ''
return true
}
//7.我同意模块
const agree = document.querySelector('.icon-queren')
agree.addEventListener('click',function(){
//切换类
this.classList.toggle('icon-queren2')
})
//8.表单提交模块
const form = document.querySelector('form')
//绑定提交事件
form.addEventListener('submit',function(e){
//8.1判断是否勾选 我同意
//如果没有勾选,弹出提示,阻止表单提交
if(!agree.classList.contains('icon-queren2')){
alert('请勾选我同意')
e.preventDefault()
}
//8.2依次判断表单项,只要有一项没通过就阻止表单提交
if(!verifyName()) e.preventDefault()
if(!verifyPhone()) e.preventDefault()
if(!verifyCode()) e.preventDefault()
if(!verifyPassword()) e.preventDefault()
if(!verifyConfirm()) e.preventDefault()
})
3. 就业统计表
<!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 initData = [
{
stuId: 1,
uname: '迪丽热巴',
age: 22,
salary: '12000',
gender: '女',
city: '北京',
time: '2099/9/9 08:08:08'
}
]
// localStorage.setItem('initData',JSON.stringify(initData))
// 1. 渲染业务
// 1.1 先读取本地存储的数据
// (1). 本地存储有数据则记得转换为对象然后存储到变量里面,后期用于渲染页面
// (2). 如果没有数据,则用 空数组来代替
const arr = JSON.parse(localStorage.getItem('data')) || []
// console.log(arr)
// 1.2 利用map和join方法来渲染页面
const tbody = document.querySelector('tbody')
const num = document.querySelector('.title span')
function render() {
// (1). 利用map遍历数组,返回对应tr的数组
const trArr = arr.map(function (ele, index) {
return `
<tr>
<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>
`
})
// (2). 把数组转换为字符串 join
// (3). 把生成的字符串追加给tbody
tbody.innerHTML = trArr.join('')
// 显示共计有几条数据
num.innerHTML = arr.length
}
render()
// 2. 新增业务
const info = document.querySelector('.info')
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')
// 2.1 form表单注册提交事件,阻止默认行为
info.addEventListener('submit', function (e) {
e.preventDefault()
// 2.2 非空判断
if (!uname.value || !age.value || !salary.value) {
alert('请输入内容后提交')
}
// 2.3 给 arr 数组追加对象,里面存储 表单获取过来的数据
arr.push({
// 处理 stuId:数组最后一条数据的stuId + 1
// stuId: arr.length + 1,
stuId: arr.length ? arr[arr.length - 1].stuId + 1 : 1,
uname: uname.value,
age: age.value,
salary: salary.value,
gender: gender.value,
city: city.value,
time: new Date().toLocaleString()
})
render()
// 2.4 渲染页面和重置表单(reset()方法)
this.reset()
// 2.5 把数组重新存入本地存储里面,记得转换为JSON字符串存储
localStorage.setItem('data', JSON.stringify(arr))
})
// 3. 删除业务
// 3.1 采用事件委托形式,给 tbody 注册点击事件
tbody.addEventListener('click', function (e) {
// 判断是否点击的是删除按钮 A 链接
if (e.target.tagName === 'A') {
// 3.2 得到当前点击链接的索引号。渲染数据的时候,动态给a链接添加自定义属性例如 data-id="0"
// console.log(e.target.dataset.id)
// 确认框 确认是否要真的删除
if (confirm('您确认要删除数据吗?')) {
// 3.3 根据索引号,利用 splice 删除数组这条数据
arr.splice(e.target.dataset.id, 1)
// 3.4 重新渲染页面
render()
// 3.5 把最新 arr 数组存入本地存储
localStorage.setItem('data', JSON.stringify(arr))
}
}
})
</script>
</body>
</html>
4. 放大镜效果
补充知识:
pageX pageY 属性可得到鼠标在页面中的横纵坐标
getBoundingClientRect() 方法其提供了元素的大小及其相对于视口的位置。
<!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>
<link rel="stylesheet"
href="./index.css">
</head>
<body>
<div>
<div class="Lbox">
<img src="./img/2.jpg"
alt="">
<div class="mask-layer"></div>
</div>
<div class="Rbox"></div>
</div>
<script>
//1. 获取DOM元素
const Lbox = document.querySelector('.Lbox')
const Rbox = document.querySelector('.Rbox')
const maskLayer = document.querySelector('.mask-layer')
//定义一个变量,用来接受定时器序号
let timeId = 0
//2. 给Lbox绑定鼠标移入移出事件
Lbox.addEventListener('mouseenter', show)
Lbox.addEventListener('mouseleave', hide)
//3. 封装显示、隐藏函数
function show() {
//显示前先清除定时器
clearInterval(timeId)
Rbox.style.display = 'block'
}
function hide() {
//设置定时器,鼠标离开延时隐藏
timeId = setInterval(function () {
Rbox.style.display = 'none'
}, 200)
}
//4. 给Rbox绑定鼠标移入移出事件
Rbox.addEventListener('mouseenter', show)
Rbox.addEventListener('mouseleave', hide)
//5.显示、隐藏遮罩层
Lbox.addEventListener('mouseenter', function () {
maskLayer.style.display = 'block'
})
Lbox.addEventListener('mouseleave', function () {
maskLayer.style.display = 'none'
})
//6.根据鼠标位置移动遮罩层
Lbox.addEventListener('mousemove', function (e) {
//e.pageX获取鼠标在页面中X轴坐标
//getBoundingClientRect()方法的.left属性,获取Lbox在页面中的坐标
//获取鼠标在 Lbox 中的坐标值
let x = e.pageX - Lbox.getBoundingClientRect().left
//y坐标还要减去滚动条卷去的头部
let y = e.pageY - Lbox.getBoundingClientRect().top - document.documentElement.scrollTop
//改变遮罩层的位置
//限定遮罩层在Lbox中的移动距离
if (x >= 0 && x <= 500 && y >= 0 && y <= 500) {
//声明mx和my两个变量,用于限定遮罩层的移动
let mx = 0, my = 0
//如果 x∈[0,90) 遮罩层不移动
if (x < 90) mx = 0
//如果x∈[90,410] 遮罩层开始移动
if (x >= 90 && x <= 410) mx = x - 90
//如果x∈(410,500] 遮罩层不移动
if (x > 410) mx = 320
// my同mx
if (y < 90) my = 0
if (y >= 90 && y <= 410) my = y - 90
if (y > 410) my = 320
//根据计算过的 mx 和 my 改变遮罩层的位置,注意加单位
maskLayer.style.left = mx + 'px'
maskLayer.style.top = my + 'px'
//7. 放大镜效果/鼠标在Lbox中移动,Rbox中的背景图位置移动
Rbox.style.backgroundPositionX = -0.92 * mx + 'px'
Rbox.style.backgroundPositionY = -0.92 * my + 'px'
}
})
</script>
</body>
</html>